Всем привет, продолжаю свою историю увлечения кулинарией и мобильной разработкой в MIT App Inventor (буду называть "аппинвентор" далее в статье) под это дело. Будет подробно расписана эволюция моего приложения для поиска кулинарных рецептов по составу (это основной базовый функционал) и запредельные, не побоюсь этого слова, возможности аппинвентора, который некоторые считают "инструментом для детей". Кстати, сразу, пока не забыл - дети, если у вас есть интерес к программированию вообще и мобильной разработке под андроид в частности, то я очень рекомендую вам ознакомиться с аппинвентором. А фуллстак-разработчикам и UI/UX дизайнерам возможно будут интересны мои мысли, на основе которых происходила эволюция интерфейса приложения, потому что путь к итоговому результату был очень неблизкий и я бы дорого дал, чтобы сразу придумать то, что получилось в итоге, пропустив промежуточные шаги и сэкономив два года, но я не верю, что это реально в принципе. Зато теперь у меня есть вся эволюция в картинках, так что есть о чем на Хабре рассказать и показать, короче, будет "комикс" ))).
Эволюция интерфейса, этап первый
Сейчас сделаю паузу и дам осмыслить читателю общую проблему разработки на данном этапе (текст под картинками надо было читать внимательно, если кто не догадался). Итак, бесконечно напихивать кнопки-картинки на один экран аппинвентор мне не позволил, кроме того, загромождение главного экрана, где сразу и продукты и рецепты, было видно невооруженным глазом, поэтому очевидным решением стало выделить под рецепты свой отдельный экран, разгрузив тем самым экран с продуктами. Явное и очевидное решение? Естественно! Лучшее? Нет, но тогда я этого не знал, не понимал и даже не догадывался.
Экран рецептов изнутри
То, что вы видите на картинке сверху это экран рецептов в режиме дизайна и моя головная боль на протяжении почти всей разработки до последнего времени. Объясняю, в чем суть. Динамические интерфейсы в аппинвенторе "из коробки" не поддерживаются, т.е. нельзя на лету создавать кнопки и прочие элементы интерфейса. Поэтому я, как настоящий фанатично упертый трудоголик, ограничил себя статическим интерфейсом с 10-ю рецептами на экране (и мне пришлось внедрить кнопки-моталки, чтобы прокручивать список рецептов на экране). Но это еще не все. Опытным путем выяснилось, что продуктов для каждого рецепта можно воткнуть не более 27, а утвари не более 11. На картинке показано только два шаблона, а ниже их таких еще 8 и при редактировании это все дергается нещадным образом (недоработка аппинвентора, я про это раньше рассказывал). В общем экран рецептов изначально оказался перегружен и никаких 30 (+3) картинок продуктов на рецепт добавить было уже нельзя. Даже 28 нельзя, т.е буквально втыкаешь новую картинку - проект отказывается компилироваться, удаляешь - все норм. Ну и бонусом прочие мелочи, связанные с ожиданием обновления экрана, неудобной прокруткой кнопками-моталками и лимитом в 10 рецептов на экране. Но, скрипя зубами, я поехал с этим экраном рецептов дальше, потому что не видел альтернатив. К слову, посмотрел недавно - для аппинвентора есть сторонние расширения, которые позволяют напихать в него динамический интерфейс, но это страшные костыли, и я их тогда не искал и даже не думал копать в ту сторону. В плане расширений я вообще ретроград и всегда пытаюсь сначала решить проблему имеющимися средствами. Ну ладно, оставляем экран рецептов пока что в покое и переходим к следующему этапу эволюции.
Эволюция интерфейса, этап второй
Здесь тут же делаю паузу и рассказываю, как я додумался до этой фичи, потому что считаю ее ключевым и вторым краеугольным камнем вообще всего приложения (первый: продукты-картинками), которая повлияла на всю дальнейшую историю разработки. Итак, до того весь продуктовый выбор отображался непосредственно текстом на кнопках, его приходилось читать, мотать-искать где что написано, потому что на экране все сразу не убиралось даже в свернутых категориях, что уж говорить о развернутых специях и прочих длинных наборах. А почему бы мне выбранные продукты не показывать в отдельной строке снизу? Сказано - сделано, стоп, а если я на них тыркну, то их же можно исключить!!! А зачем тогда мне длинные нажатия на зеленые кнопки, перекрашивания, парсинг текста что включено, а что выключено? И зачем мне тогда вообще весь этот зеленый матрас, только лишь для выбора продуктов? Опа... Ладно, пока идем дальше
Эволюция интерфейса, этап третий. Пользовательские жалобы
То тут, то там (да и теперь до сих пор) стал появляться недовольный народ, который не понимал, что какая картинка обозначает. Кто-то честно признавался, что не помнит флаги стран, кто-то не отличает одну рыбу от другой, кто-то путался в специях, но никто не сказал, что "я мол не знал что за картинка, а потом ткнул на нее и сразу как всё понял", хотя я объяснял всем и каждому, что при тычке на картинках всегда рядом появляется подсказка, что сие такое. Ладно, будет вам текст, первая попытка:
Опять я, упоротый трудоголик, решил проблему через не то место и огреб на ровном месте кучу новых проблем. Итак, никакого автоформатирования у меня тут не вышло, т.е. красиво скрыть/показать текст рядом со статичными картинками оказалось нельзя. Размер текста меняется, картинки в зависимости от этого пляшут, посему пришлось разруливать через дубликаты, т.е. на каждую категорию два набора кнопок - один с текстом, другой без, и скрыть/показать то один, то другой при смене режима. На все продуктовые категории моего запала не хватило, но я точно помню, что сделал для специй, зелени, мяса, рыбы и сыров. Дальше выяснились три ключевых затыка:
У пользователей на разных телефонах текст все равно обрезается, и то, что на моей трубе выглядит отлично, на другой вообще криво
Удвоение кнопок на главном экране привело к тому, что проект перестал компилироваться
Крепко задумался, что в случае, когда придется прикручивать англоязычность, я очень сильно огребу со всеми этими динамическими лейблами и текстом на них
Короче, режим "картинка с текстом" оказался мертворожденным, но он подвинул меня на изучение и добавление нового элемента интерфейса аппинвентора, а именно ListView, где к тому времени появились новые шаблоны (Image,MainText,DetailText), а до того их не было (Changes between nb186a and nb187 (August 22, 2021)) - где-то год прошел с момента этого апдейта и до времени, когда я сподобился это все прикрутить. У меня на ютуб-канале все этапы разработки запротоколированы, теперь-то стыдно конечно, что я довольно долго пинал свои button/label и тормозил с переходом на вот такую простоту и красоту, но, лучше уж поздно, чем никогда, вторая попытка:
Удобненько, да не совсем, да, я заменил 100+ кнопок на 20+ листов и проект снова начал нормально компилироваться, но каждая открытая категория это новый открытый лист, что там мотается - лист или экран, черт его разберет, стоп, минуточку, у меня же были повара и бутылки уже в горизонтальный ряд расставлены, давай-ка теперь и с категориями тоже так сделаем.
Наконец-то решились абсолютно все проблемы с перегрузом главного экрана, выбором продуктов и динамическим UI. Кнопки ушли вместе с матрасом, приложение значительно облегчилось, также теперь достаточно при добавлении нового продукта просто загрузить картинку в приложение и добавить поле в внешней базе (не надо совать картинку на кнопку, как раньше). И никаких проблем с мультиязычностью в будущем. Кстати, я тут не рассказываю про бэкенд, там тоже подводных камней было немало, но они скучные по большей части и точно не такие интересные, по сравнению с эволюцией фронтенда. Всего лишь раза 4 переделывал базу, мухаха ))). Ну ладно, возвращаясь к интерфейсу главного экрана - когда ничего не выделено, вместо двух списков образуется полным-полно пустого места, что бы туда воткнуть? Ну конечно же 10 случайных рецептов в формате ListView:
Стоп, у меня и на главном экране теперь опять рецепты, и старый экран рецептов никуда не делся, дубликат, непорядок, но я же через ListView на главном не сделаю ни кучу картинок продуктов, ни подбор бутылок, ничего, зато можно вывести хоть тыщу рецептов сразу на главный экран моментально, а с другой стороны старый экран рецептов придется все равно рано или поздно убирать, потому что он тормозит и утяжеляет приложение - я к тому моменту понял, что это самое слабое место приложения по всем параметрам - статический интерфейс с 500+ картинок и кучей в принципе лишнего кода, поскольку я уже хоть как вывожу на главный экран рецепты через ListView. Да, и кстати, на этом этапе аппинвентор снова начал отказываться компилировать проект из-за перегрузки опять главного экрана, и мне пришлось, например, вынести из него на другой экран модуль обновления баз и заняться рефакторингом кода, удалением одних картинок тут уже стало не разрулить. Так как же убрать экран рецептов и сделать на главном динамическую загрузку также, как и там, но без тормозов и кнопок перемотки?
Думай
Думай!
Думай!!!
Пока придумывается, расскажу про кое-какие новенькие штучки аппинвентора
В феврале 2023-го разработчики аппинвентора добавили функционал для работы с листами (Changes between nb191 and nb190a (February 17, 2023) - Add functional list operators like map, filter, reduce, and sort), который многократно ускорил у меня практически всё. Буквально так - был и тормозил цикл с ифами и нету цикла и тормозов. Очень рекомендую внедрять всем, кто ковыряется в аппинвенторе, это must have.
Выше на картинке часть моего проекта и глаза разбегаются где тут и что. Это самая главная проблема конечно - навигация, никаких "файндов" из коробки не предоставляется кроме двух - можно прыгать по ошибкам и можно перейти на функцию из места, где она вызывается (Highlight Procedure). Но я нашел еще один нетривиальный метод перехода на элемент интерфейса, о котором сейчас вам расскажу, кому-то да пригодится. Все просто до безобразия - нам нужно найти и перейти на событие клика какой-нибудь кнопки, которое мы потеряли в дебрях проекта - находим кнопку и вытаскиваем это событие через левую панель, получаем ошибку, что событие уже определено и прыгаем на эту ошибку, тогда он будет перемещаться между старым событием, где нам нужно что-то поправить и новым пустым - которое мы удалим после исправлений старого. Но инициализацию глобальной переменной таким способом к сожалению не найдешь.
Возвращаясь к моей проблеме динамического списка рецептов на главном экране - самая длинная вертикальная цветная простыня на экране это и есть решение. Сейчас будут подробности. Кульминация все ближе и ближе.
Эволюция интерфейса, этап четвертый. RocknRolla
Внезапно я вспомнил про то, что у аппинвентора есть такой компонент, как WebViewer, который рекомендуется использовать как кастрированный браузер для просмотра страниц в интернете. Я собственно им рецепты-то и открываю, таак, стоп, а только ли в интернете? Локально можно? КОНЕЧНО МОЖНО! Было бы странно, если бы нельзя. А что есть у WebViewer'а, чтобы взаимодействовать с другим функционалом аппинвентора?
Можно запустить javascript, можно обменяться строкой, все, мне вполне хватит. Итак, план такой - аппинвентором генерим для рецептов html-страницу с css-ом и javascript'ами скармливаем его вьюверу и отображаем его на главном экране аппинвентора, далее через скрипты передаем туда-сюда все, что нам нужно и меняем интерфейс динамически. По итогу у меня там и через innerHTML полным-полно всего меняется, расписывать подробности не буду, потому что это базовый HTML+CSS+Javascript и это самая разжеванная тема везде где только можно, а я ее преподавал (20 лет назад), вспомнил, пригодилось.
Ну вот и четвертый краеугольный камень приложения - динамический интерфейс по красоте, сколько-угодно картинок, куча самосоздающегося кода на одной html-страничке и никаких проблем с перегрузами. Единственная теперь проблема это автозагрузка превьюшек из ютуба, потому что для сотни рецептов на главном экране это ай-ай-ай. Внимательный читатель спросит меня - а где же третий краеугольный камень приложения? А вон он на картинке, микрофончик справа от дамы видите? Голосовой поиск через внешнее расширение был прикручен в процессе и он отлично взаимодействует с панелью быстрого доступа. Одного без другого точно бы не было, как собственно и всего остального в этой разработке - одно тянется за другим, новый функционал вырастает из старого, старый умирает, как умер первый экран рецептов, хнык. Я же его незамедлительно грохнул после того, как перенес весь функционал в WebViewer. И мне теперь под аналогичный динамический интерфейс и винную карту переделывать, ну это будет дело десятое, сначала мультиязычность и винный погреб, а то я уже забыл где у меня там какие бутылки припрятаны, а надо бы отметить юбилей.
Заканчиваю видеобзором последней на данный момент 10-ой версии и ссылками на скачку, всем спасибо за внимание.
Прямая ссылка (если скачка с гугл-плей недоступна)
p.s. Для создания подобного приложения в одно лицо вам понадобятся (всего лишь):
На фронтенд: MIT App Inventor, HTML, CSS, Javascript, Photoshop
На бэкенд: Google Sheets + App Script + Youtube API
Опыт собственный (много) и куча свободного времени
p.p.s. Раньше я рассматривал App Inventor как средство для создания прототипа приложения, думал что мне от него много не надо, типа накидаю быстро в аппинвенторе основной функционал, а потом, если припрет, перепишу готовое, например на Unity. А теперь думаю - а зачем переписывать?