Планировал за вечер доделать систему ответов. Но не справился. Работал над системой ответов и внезапно всплыл неприятный момент: 1) История сообщений грузятся динамически пачками по Х сообщений. Каждое соообщение может ссылаться на какое-то сообщение из истории переписки. 2) Сообщение на которое ссылается текущее сообщение может не быть загружено. В этом случае его нужно подгрузить. Иначе приложение будет думать, что сообщение удалено:
И тут самый сок. За что я не люблю Flutter/мобильную разработку - это за то, что нельзя просто взять и загрузить то, что недостает:
Начались пляски с бубном на тему того как же оптимальней подгрузить эти недостающие сообщения. Перепробовал разные методы, самый оптимальный (на мой взгляд) - загружать допсообщения в момент, когда грузятся основные сообщения.
Ничего умнее и оптимальнее придумать не смог. Другие вариант подгрузки приводят к ожиданиям из-за обращения к БД в следующем кадре; А еще они приводят к хитровымудренным схемам перестройки интерфейска, что мне совсем не понравилось (работы там и без этого хватает).
Ранее писал что буду переделывать систему вывода таймстемпов т.к. в ней были выявлены ошибки. Переделал:
1/3
Таймстемпы теперь всегда в правом нижнем углу
Также состояние доставки перенес в самый правый угол сообщения.
Сейчас сообщения-ответы на сообщения отправляются, приходят и нормально выводятся. Проблем не должно быть.
Далее берусь за работу над контекстым меню сообщений (это когда жмешь на сообщение и возникает меню с вариантами действий). Вот его нужно добить и можно будет редактировать сообщения :)
После контекстного меню буду думать над загрузкой медиа на сервер (для обмена файлами). По идее серверная часть уже реализована, нужно бы научить приложение загружать медиа на сервер и обрабатывать ошибки загрузки :)
Вроде интерфейс получается. Вспомнил первые наброски интерфейса:
Примерно так он выглядит сейчас:
-- По вечерам разрабатываю сервис для общения на Go & Flutter. Кому интересно, можете подписаться куда-нибудь на меня, попробуете его в числе первых. Постепенно буду продолжать делиться успехами разработки сервиса.
Ранее писал о том как делал механику ответа на сообщения (свайп). Была проблема: любое свайпнутое сообщение сдвигало аватарку пользователя. Исправил этот момент:
Еще добавил в поле ввода отображение сообщения на которое пишется ответ. Вот первая попытка добавить:
А это последняя версия на сегодня. Вроде выглядит неплохо для ранней версии. Во всяком случае полагаю что располагать ответ на сообщение над полем ввода - это удобно и функционально:
Работает так: свайпаем любое сообщение (1) и в поле ввода оно появляется (2). Вроде все просто, у всех примерно так и сделано:
Заметил что сообщения у меня сделаны не лучшим образом: много места занимают отступы (3), медиа небольшого размера, текст сообщения (если есть) находится над медиа (1), зачем-то добавил скругления углов медиа (2) (ну и цвета очень пестрые, яркие):
Исправлял эти моменты сегодня, теперь медиа пытается занять всю ширину сообщений:
Тут нужно дату отправки бы отобразить под медиа
Если сообщение содержит ответ или заголовок, то медиа выглядит так:
Видите таймстемп съехах? Да-да, снова под нож пойдет, придется дорабатывать.
Конечно есть много недочетов и мелочей, но в целом дело движется :)
Читаю некоторые ответы под своими постами на тему разработки, интересные реакции на посты. Некоторые люди тут все же раздражают. Наверно они и ставят иконки рвотных масс, каках и тп 😂
Во-первых у кого-то навязчивое желание научить меня тому, что мне не следует писать сервис для общения 😂 Потому что сервисов очень много 😂 Ну что с того что много, я же учусь. Недавно паяльник за 300 руб разобрал и починил, давайте, сойдите с ума 😂😂😂 Могу рассказать как наушники за 50 руб починил, чтобы вообще до бешенства довести :)
А что мне делать по вашему мнению? Ходить баки пинать? Шататься по городу в поисках острых ощущений? Может путешествовать? А может алкогольчиком баловаться? А может зарабатывать тк время=деньги?
Давайте, начинайте учить кому и что в жизни делать. Все только сидят и ждут кто бы научил. В общем, советуйте свои советы себе сами 😂 А мы продолжим постепенно работать.
Возможно опубликую тут что-то интересное по работе, историй с работы у меня не то чтобы много, а очень много. Да еще и такие, что здоровенного кота с здоровенной лампой придется притащить 😂😂😂
Пока на этом все, буду дорабатывать таймстемпы и систему ответа на сообщения. Также доберусь до системы взаимодействия с сообщениями посредством контекстного меню. Отправка и прием сообщений работают, нужно наконец уже добиться чтобы редактирование, удаление и прочий функционал тоже работал.
-- По вечерам разрабатываю сервис для общения на Go & Flutter. Кому интересно, можете подписаться куда-нибудь на меня, попробуете его в числе первых. Постепенно буду продолжать делиться успехами разработки сервиса.
Подозревал, что нельзя просто так взять и интегрировать разработанную ранее механику свайпов в свой проект. Да, угадал. Из-за моей неопытности и неполного понимания принципа работы Flutter, проблемы начали сыпаться как из рога изобилия. Вот что получилось:
- во-первых сливер с хэдерами (а это сообщения и даты) начали перехватывать свайпы и сообщения не получали информации о том, что их пытаются свайпнуть - во-вторых мой сливер с хэдерами, который "типа работает как надо", оказалось что он не совсем работает. А если точнее, я не понял ранее за что отвечал код, обрабатывающий касания пальцев и удалил его. Ну вот понял зачем, лишним, как оказалось, он не был 😂 и без него сообщения вообще не получали информации о том, что их свайпают - в-третьих, пришлось разбираться как переопределить области свайпов, чтобы палец свайпал нужное сообщение, а не соседнее или какое-то случайное - в-четвертых аватраки перестали смещаться полем ввода
Помимо этого нашлась еще охапка проблем, но хватит уже о грустном 😂
Что нужно доработать
Аватарки, вернее их горизонтальное смещение. Оно уже неплохо реализовано (в видео видно), но нужно добить их. Сейчас каждое сообщение группы смещает аватарку, а нужно чтобы только "нужное" сообщение смещало ее:
Да вроде это и несложно сделать, нужно просто посмотреть где находится аватарка и решить нужно смещать ее или нет.
После того как добью свайпы перейду к полю ввода сообщения. Нужно будет добавить в поле ввода отображение свайпнутого сообщения (на которое пишется ответ).
-- По вечерам разрабатываю сервис для общения на Go & Flutter. Кому интересно, можете подписаться куда-нибудь на меня, попробуете его в числе первых. Постепенно буду продолжать делиться успехами разработки сервиса.
Читал как-то книжку по Dart/Flutter на русском и она мне не понравилась: сухо, скучно. А местами ну прям вообще, напомнило адскую черепашку с урока информатики:
В общем, может от нее польза и была, но читать было трудно. Называть автора не буду т.к. на вкус и цвет не всем мидии нравятся. Кто-то предпочитает улиток или слизней 😂 Глотать сразу 😂
Я не особо любитель что-то делать, а потом узнавать что так не делают. Например писать код, который потом придется переписывать. Потому временами ныряю в отечественную и зарубежную литературу. А чтобы оседало в голове, запускаю код из примеров, перевожу, делаю заметки. Ну а как иначе-то?
На днях доперевел небольшую часть книжки, которая мне понравилась. Хочу поделиться, вдруг кому-то поможет. Не все же могут перевести? Или могут?
Могут или не могут, вот первая глава без воды, если будет полезно, то с вас как минимум плюсик: ссылка
Позже еще допереведу, если не забуду, то скину остальные главы и всю книжку целиком с автором и названием (еще глав 10, если не ошибаюсь). Можете угадать автора? Может кто читал, хотя именно эту вряд ли.
-- По вечерам разрабатываю сервис для общения на Go & Flutter. Кому интересно, можете подписаться куда-нибудь на меня, попробуете его в числе первых. Постепенно буду продолжать делиться успехами разработки сервиса.
Неделю не было новостей по сервису для общения. Пора это исправить!
В моих планах было перейти к обмену сообщениями: отправка, прием, запись в БД, отображение пришедшего сообщения. А еще была маленькая задачка - зафиксировать иконку даты в истории переписки. До этого я просто добавил даты и вроде как дело осталось за малым: просто зафиксировать одну из дат в верхней части истории. Ну и началось. Кто же знал что будет непросто 😂
Вот так в итоге работает отображение дат в окне переписки:
Вообще, в Flutter есть такая вещь как виджеты и благодаря им даже новички из коробки могут создавать достаточно сложные вещи в Flutter. Это что-то типа куба в Unity: открываешь сцену, кидаешь куб и думаешь, что сейчас как сделаешь супер-игру, как она всем понравится... А потом оказывается, что это была рекламная кампания и чтобы сделать действительно что-то производительное, придется в тонкостях разбираться что и как работает:
Пустая сцена с кубом
Это уже по опыту говорю, писал TotalReload, знаю как и что там работает:
Скрин сцены Total Reload
Виджеты предоставляют широкий спектр возможностей и с их помощью можно было бы сделать систему дат, но с ограничениями. Есть такая вещь как Sliver, он позволяет удобно реализовывать сложные интерфейсы взаимодействия. Sliver-ов великое множество и вроде как они покрывают почти все потребности разработчиков.
Возникла проблема. Готового решения я не нашел. Да и нет его похоже. Пытался прикрутить имеющееся стандартное решение (помним, что визуально это не то, что нужно), но и готовое решение приколхозить нормально не получилось из-за имеющихся багов. Чтобы не быть голословным, вот: Ссылка №1 на Git с багом Ссылка №2 на Git с костылем Ссылка №3: разработчики поднимают эту тему
Прозрачный AppBar и исправление бага - это уже уникальный интерфейс 😂😂😂
Про костыль: при открытии чата нужно пролистать список сообщений в самый низ. Понятно что список загружаю не весь, а только N последних сообщений. Вот их-то и требуется пролистать вниз.
Но из-за бага нельзя узнать сразу значение низа, то есть высоты всего списка. А получить его можно через кадр. В итоге разработчики сделали такой незаметный костыль: список пролистывается до максимального значения(но не до конца), а потом анимацией список докручивается до низа и по мере прокрутки Flutter обновляет максимальное значение для пролистывания. Чудо-код, который это умеет и работает стабильно:
Но это решение, очевидно, плохое. Открываешь чат, а он что-то листается куда-то... В итоге пришлось разбираться как решить эту проблему. Ведь если нельзя, но очень нужно, то все же что-то придумать можно 😂
А советчики этого костыля могут сами им и пользоваться:
Ну и пользуйтесь своим решением
Решение
Решение достаточно веселое. Flutter - это некая кроссплатформенная система рендера, которая управляет процессом отрисовки. Очень грубо, очень по рабоче-крестьянски, но в самом первом приближении это так. Система работает на основе деревьев. И на любой вопрос типа: почему используются деревья, зачем системе рендера кэш и границы, зачем система разделена на элементы и переиспользует их... ? На все это примерно один ответ - чтобы для пользователя интерфейс быстро работал.
Еще стоит отметить, что управлять тем, что выводится на экране можно с нескольких абстракций.
(1) Самый верхний уровень - виджеты. Это буквально готовые кирпичики, берешь и используешь. Глубокого погружения в тонкости рендера не требуется. Первое приложение можно написать ничего не зная.
(2) Далее идет CustomPaint. Это виджет, который умеет на себе рисовать. Что-то типа приложения Paint: берешь холст и рисуешь примитивы. Им отрисованы градиенты окошек сообщений. По сути это продвинутый виджет, сложность понимания принципа работы примерно как с виджетами.
(3) RenderObject - это уже интереснее, это то, как все рисуется в Flutter. И сложность понимания внезапно поднимается до "нужно понять как все тут устроено". Отмечу, виджеты уже сами в себе содержат механизм RenderObject, но от пользователей он скрыт. Если вдруг потребуется сделать такой виджет, которого нет среди стандартных виджетов, то придется разбираться, как устроена система рендера и используя ее собирать свой собственный виджет. Собственно этим я и занимался. Пришлось сделать виджет, который визуально умеет делать все то, что делает стандартный SliverStickyHeader от Flutter. Но важно: костыли нужно убрать, AppBar нужен прозрачный.
Теперь даты красиво ездят туда-сюда, вроде эстетично и глаз радуется :)
Далее работаю над отправкой и приемом сообщений.
-- По вечерам разрабатываю сервис для общения. Кому интересно, можете подписаться куда-нибудь на меня, попробуете его в числе первых. Постепенно буду продолжать делиться успехами разработки сервиса.
Привет, Пикабу. Мне 23 года и недавно я решил начать учить польский. Я с детства учу английский, владею им на хорошем уровне и знаю, насколько мне тяжело дается учеба. Просто зубрить слова и правила - это не мое, становится скучно моментально и, что самое главное, не запоминается практически ничего. Основываясь на этом опыте, я понимал, что мне нужно погружение в контекст. Так как польский (также как и русский) относятся к славянским языкам и в них довольно много похожих по звучанию и значению слов, я стал сразу пытаться начать читать.
И тут начались первые проблемы. На сайтах, на которых есть тексты, адаптированные для уровня А1-А2 читалка без встроенного переводчика. Импортировать тексты в Apple Books это совсем не то и неудобно. Я начал искать альтернативы.
Приложение, которое мне понравилось по функционалу, - это LingQ. У него есть встроенная библиотека текстов, перевод слов по тапу, карточки и, казалось бы, вот он, идеальный вариант. И это он, если бы не цена в 13 фунтов ежемесячно. На хобби тратить столько денег на подписку я посчитал не целесообразно.
Помимо изучения языков, я увлекаюсь программированием на пайтон и вайбкодингом.
Так и родился LinguaVibe.
Что вообще получилось
LinguaVibe - это Flutter-приложение для чтения иностранных текстов. Сейчас поддерживает 5 языков: польский, испанский, немецкий, французский и английский. Интерфейс - на русском.
Основная фича: ты вставляешь текст (или импортируешь статью по URL), читаешь, и когда встречаешь незнакомое слово - тапаешь на него. Приложение отправляет всё предложение в LLaMA через Groq API и получает перевод с учётом контекста. Не просто «слово → перевод», а полноценный разбор: начальная форма, перевод, грамматика и даже пример предложения.
Вторая по важности фича: ты можешь вставить свой ключ Groq API, который получается совершенно бесплатно и получить практически весь функционал приложения совершенно бесплатно, с условием, что у вас установлено приложение с названием из 3 букв.
После этого сохраняешь слово в словарь, а потом учишь его через встроенные карточки с системой интервального повторения (SRS, метод Лейтнера).
Главное меню приложения
Стек и архитектура
Тут всё просто, без enterprise-булщита:
Фронтенд (мобилка):
- Flutter (Dart) - потому что кроссплатформа и горячая перезагрузка
- Provider - стейт-менеджмент, без Riverpod-магии
- Isar - локальная NoSQL база. Быстрая, асинхронная, и главное - у меня отдельная база на каждый язык (`isar_pl`, `isar_es` и т.д.)
- flutter_tts - озвучка слов. Польский, испанский, немецкий - всё произносит
Бэкенд:
- Node.js + Express - лёгкий сервер на соседнем репозитории
- Docker - контейнеризация, потому что я не хочу настраивать сервер руками в 3 часа ночи
- Caddy - reverse proxy с автоматическими HTTPS-сертификатами. Lets Encrypt сам всё делает, красота
AI:
- Groq API - LLaMA 3.1 8B для быстрых переводов по тапу, LLaMA 3.3 70B для генерации примеров и переводов заголовков. Groq быстрый - ответы за 200-300мс, это важно когда ты тапаешь на слова в тексте
Словарь
Как я это кодил
Буду честен - я вайб-кодил с ИИ-помощниками. Opencode, Cursor, Claude - всё было. Я Python-разработчик, Dart я до этого практически не трогал. Но с ИИ-ассистентами это оказалось не так страшно.
Архитектуру продумал сам: сервисы, репозитории, провайдеры. А детали реализации делал с ИИ. Это реально работает, если ты понимаешь что хочешь получить.
Вот так выглядит перевод по тапу
Грабли, на которые я наступил (и закрыл)
Вот тут самое интересное для технарей. Перед релизом пришлось закрывать несколько серьёзных дыр.
1. APP_SECRET_KEY в коде
Изначально ключ бэкенда был захардкожен в `server_config.dart`. Это ужасно - любой может декомпилировать APK и получить ключ.
Решение: перенёс ключ в `--dart-define=APP_SECRET_KEY` при билде. Ключ хранится в `.env` файле (который в `.gitignore`), а билд-скрипт подставляет его через `dart-define`. В коде - `const String.fromEnvironment('APP_SECRET_KEY')`. При декомпиляции ключ не найти в plaintext.
2. SSRF-атаки в веб-парсере
У меня есть фича импорта текстов по URL. Пользователь вставляет ссылку, приложение парсит статью и вытаскивает текст. Проблема: если пользователь вставит `http://localhost:3000/admin` или `http://169.254.169.254/latest/meta-data/` (AWS metadata)?
Решение: в `WebParserService` добавил валидацию URL:
- Проверяю что схема - только `http` или `https`
- Блокирую localhost, 127.0.0.1
- Блокирую приватные сети (10.x.x.x, 172.16-31.x.x, 192.168.x.x)
- Блокирую AWS/GCP metadata (`169.254.169.254`)
// Блокируем SSRF
if (uri.isLoopback || uri.isPrivate) throw Exception('Blocked');
if (uri.host == '169.254.169.254') throw Exception('Blocked');
3. Накрутка лимитов
У меня freemium-модель: бесплатно 10 переводов в день и 3 импорта URL. Premium - безлимит. Но что если пользователь будет спамить запросы?
Решение: на бэкенде - rate limiting по userId. На клиенте - счётчики в SharedPreferences с ежедневным сбросом. Перед каждым запросом - проверка лимита. Если превышен - кидается `SubscriptionTranslationLimitException` и показывается диалог с предложением купить Premium.
4. Вебхуки ЮКассы и идемпотентность
Для Android-оплаты использую ЮКассу. Бэкенд создаёт платёж, пользователь оплачивает в WebView, ЮКасса шлёт вебхук. Проблема: вебхук может прийти дважды (сеть моргнула, таймаут, retry).
Решение: на бэкенде - идемпотентная обработка вебхуков. Каждый платёж имеет уникальный ID, и если вебхук уже обработан - повторный игнорируется. Плюс проверка HMAC-подписи от ЮКассы, чтобы никто не мог подделать вебхук.
5. WebView для платежей
На Android оплата идёт через WebView с ЮКассой. Нужно было убедиться, что пользователь не уйдёт со страницы оплаты и что deep link сработает корректно.
Решение: `webview_flutter` с `NavigationDelegate`. Разрешаю навигацию только на домены `yookassa.ru` и `yandex.ru`. Ловлю deep link `linguavibe://payment-success` через `onNavigationRequest` и `onUrlChange` - как только редирект на наш scheme, закрываем WebView и обновляем статус Premium.
Самый сок в том, что все эти уязвимости (включая защиту от SSRF в парсере и дыру в WebView) мне подсветил не платный аудит и не Claude, а бесплатный Qwen 3.6 в OpenCode, когда я ради прикола скинул ему структуру проекта и спросил: „Где я тут обосрался?“. Нейронка буквально ткнула меня носом в безопасность, расписала, что у меня не так и предложила фиксы.
Читалка
Что умеет приложение сейчас
Чтение:
- Вставка текста вручную
- Импорт статьи по URL (парсинг с фильтрацией мусора - рекламы, privacy policy и прочего)
- Тап на слово → AI-перевод с контекстом
- TTS-озвучка каждого слова
Словарь:
- Все сохранённые слова с поиском
- Ручное добавление слов (с AI-генерацией перевода и примера)
- Редактирование переводов
Карточки (SRS):
- Метод Лейтнера: 6 коробок с интервалами 5 мин → 4 ч → 1 день → 3 дня → 7 дней → 14 дней
- 3D-анимация переворота карточки
- Настраиваемый лимит слов за сессию (10-100)
- Слова на 5-й коробке считаются освоенными
Настройки:
- Groq API ключ (вставил свой кюч - тогда безлимит)
- Темы: светлая, тёмная, системная
- Стиль плиток: градиент или монохром
- Экспорт/импорт словаря в JSON (Premium)
- Серия дней (streak) - мотивация не бросать
Premium:
- iOS: In-App Purchase, 449 ₽/мес
- Android: ЮКасса, 349 ₽/мес
- Безлимитные переводы и импорты
- Если вставишь свой Groq API ключ - лимиты снимаются и без подписки
Бонус: приложение весит всего 20 МБ в RuStore. Оптимизировал сборку, убрал лишнее, и получилось довольно компактно для Flutter-приложения.
Карточки с интервальным повторением
Где скачать и потестить
На данный момент приложение доступно только в RuStore под Android. В будущем планируется релиз под iOS в AppStore.
Есть такое англоязычное приложение Fantasy Hike - превращает твои шаги в путешествие по фэнтези-миру. Идея огонь, я хотел пользоваться, но там странное ограничение: бесплатно можно пройти только полтора километра в день. Сделал 10 000 шагов, а в приложении продвинулся на полтора километра. Хочешь больше - плати за подписку.
Понятно, что ребятам надо как-то зарабатывать (оплачивать серверы, разработку, продвижение, дизайнеров и тд). Но 1500 метров в день для бесплатного пользователя слишком строгое ограничение. Оно скорее про то что "не дадим нормально пользоваться, пока не заплатишь".
В итоге сел и за пару вечеров завайбкодил свой Lord of the Steps
Суть примерно та же:
Маршрут Фродо из Шира до Роковой Горы 2 350 км по канону
При 10 000 шагов в день полный путь займет около 9 месяцев
Шаги читаются через Health Connect (Android) и HealthKit (iOS), всё с Mi Band/Apple Watch/Garmin/Wear OS подтягивается само
Виджет на главный экран (шаги, км и где ты сейчас на карте)
Можно собраться компанией объеденившись в общие группы
Кстати, у Fantasy Hike реально классная анимация. В нем человек ходит по карте, ландшафт меняется и время суток (видно что вложились). Я такое повторять не стал, сделал проще - просто прогресс по маршруту.
Опыта в Android и iOS у меня вообще не было. Просто давно хотелось попробовать опубликовать что-нибудь в сторах, посмотреть как это устроено. С сlaude сode это оказалось реально и не за пол года, а за несколько вечеров. Собрал быстро базовую часть, потом полировал интеграцию с Health Connect и фоновую работу (там свои приколы), виджеты на ios и android, группы и тд.
Приложение есть в Google Play, App Store и RuStore, потихоньку набирает пользователей без рекламы и продвижения (сейчас около 700 активных пользователей). Видеть, как живые люди реально идут от Шира до Мордора приятно.
Добрался до работы над чатами и все еще работаю над созданием персональных чатов между пользователями. Параллельно пробрасываю логику груповых чатов и каналов. Но это не все, еще и интерфейсом занимаюсь:
На вырвиглазные сочетания цветов пока не обращайте внимания. Подбираю специально контрастные цвета, чтобы можно было легко заметить просчеты. Иконки тоже почти случайно раскидал, взял первое попавшееся что было в "стандартном наборе разработчика".
Странное дело, на экране монитора интерфейс воспринимается иначе, не так как на мобильном устройстве (расположение и размер элементов). Из-за этого в последнее время смотрю как выглядит сборка прямо на устройстве.
В окно поиска контактов/создания чата внизу добавил размытие и пару кнопочек:
Размытие экрана унифицировал немного, теперь его можно подключать к каждому окну отдельно. Работает хорошо, но насколько понимаю, неоптимально. Потом может быть вернусь еще к нему.
Сверху сделал заготовку с областью для сторис (красная область), снизу меню с кнопками для быстрого доступа к функциям приложения. Над звонками еще не работал, но планы под это дело имеются.
Над размытием пришлось много возиться. Очень много. Если хочешь сделать что-то не похожее на интерфейс 2000-х, то для этого нужно использовать передовые технологии 😂😂😂 Например размытие по градиенту 😂😂😂
Не знаю в чем проблема сделать эффективное размытие в Flutter, но проблема у них есть. Есть и куча костыльных плагинов и куча заплаток для Flutter. Для Flutter есть куча всего созданного разными разработчиками и подключается каждый пакет отдельно. А вот на Unity3D размытие можно было бы добавить в пару кликов: кидаешь Canvas, пишешь шейдер какой хочешь, позиционируешь слой размытия где хочешь, настраиваешь очередность рендера, ползунками настраиваешь парамтеры размытия. Учитываешь в шейдере особенности железа и вуаля, все замечательно работает. Знаю о чем говорю, в Total Reload работал над графикой:
Разработчики Flutter мне, наверно, бы сказали: нравится Unity? Ну и катись:
В направлении удобно пристроить 5-ю точку 😂
В Unity3D как хочешь, так и делаешь. Хотя вру. В Unity3D работает немного иначе: ты не делаешь баги (если не делаешь), но за тебя делает баги Unity3D 😂 Опыт работы в ней лет 10, так что, наверно, знаю о чем говорю. Да и правка и репорт на баги в Unity3D выглядят примерно так:
В ощем не соскучишься
Есть интересный момент. Минимальный вес приложения на Unity - около 15 мб. Это связано с тем, что в проект добавляется физ. движок. Это все же инструмент разработки для игр. В том числе и из-за веса решил создавать проект не на Unity, а на Flutter. На днях узнал что минимальный вес приложения на Flutter тоже около 15 мб 😂😂😂
Структура клиента
Ранее в посте сетовал что я сам себе злобный буратино и мне не нравится то, как организовал структуру проекта. В итоге сегодня мои руки были по локоть в крови от усиленного рефакторинга кода. В какой-то момент решил проиндексировать каталоги проекта, чтобы они располагались в том порядке в котором проиндексированы а не по алфавиту:
Не знаю можно создавать имена каталогов начинающиеся с цифр или нельзя. Вообще у программистов нельяз. Но если очень хочется, то, наверно, все же льзя.
Системные вызовы в приложении
Приложению очень важно быть в курсе того, что сейчас с ним происходит: свернуто оно или пользователь его закрывает.
Ранее писал код под настольные компьютеры, веб и мобильные устройства. Так вот, у всех свой набор методов, которые вызываются при наступлении того или иного события. На телефонах за эти события отвечает WidgetsBindingObserver, на компьютерах WindowListener, на web-версии уже не вспомню что, но я вовремя психанул и сделал общий интерфейс на все и вынес его в отдельный файл чтобы не сойти с ума от поисков где что вызывается:
Теперь в одном месте все события. Не знаю почему в Flutter не унифицировали все это дело. В Unity3D, вроде как, было проще. OnApplicationQuit прописываешь и понимаешь что если он вызвался, то приложение закрывается и не имеет значения на чем работает приложение: планшет, мобильный телефон или еще что-то.
Работа над чатами
Вообще все эта работа проходила на фоне работы над созданием чатов. Я промахнулся, не рассчитал 😂 В общем как-то так получилось, что в процессе работы меня переклинило и решил что нормальная тема когда человек нажимает кнопку типа "Создать чат" и создает чат с человеком.
Чат должен создаваться просто: нажал на пользователя и отправил сообщение. Если отправил сообщение, то чат создался. Не отправил - не создался. А вот каналы и групповые чаты можно создавать через нажатие на кнопку "Создать ***".
В итоге переписывал немного серверную логику с учетом замечаний, клиента немного переписал, познакомился с парой людей на улице (которые недовольны мессенджерами), скинул им ссылку на группы чтобы подписались на меня. На данный момент добавляю в клиентское приложение вебсокеты, работаю над созданием чатов, обменом сообщениями, откладываю копейку на серверное железо 😁.
Пожалуй все на сегодня, отпишусь как появятся новости 😁.
-- Кому интересно, можете поддержать (лайком) или подписаться куда-нибудь на меня, попробуете сервис в числе первых. Постепенно буду продолжать делиться успехами разработки.