Разработка мобильных приложений на Python. Библиотека KivyMD
Приветствую! Сегодня речь снова пойдет о библиотеке KivyMD — наборе виджетов для кроссплатформенной разработки на Python в стиле Material Design. В этой статье я сделаю не обзор виджетов KivyMD, как в недавней статье, а, скорее, это будет материал больше о позиционировании виджетов. Что-то похожего на туториал по разработке мобильных приложений на Python для новичков здесь не будет, так что если впервые слышите о фреймворке Kivy, вряд ли вам будет все это интересно. Ну, а мы погнали под кат!
На днях скачал из Google Play демонстрационное приложение Flutter UIKit:
Некоторые элементы UI отличаются, не в силу каких-то технических особенностей, из-за которых нельзя было получить идентичный результат, а просто я посчитал, что так будет более органичней (например, черный Toolbar, по моему мнению, совсем не смотрится).
Итак! Что бросается в глаза, глядя на экран, который мы будем воспроизводить? Прозрачный фон переднего layout. В Kivy такую возможность предоставляет FloatLayout, который позволяет размещать в себе виджеты и контроллы один над другим следующим образом:
Схематично наш экран будет выглядеть так:
Разметка этого экрана довольно простая:
Почему я говорю о FloatLayout, если наш экран унаследован от Screen?
Все виджеты во FloatLayout позиционируются от нижнего левого угла, то есть, на экране им автоматически присваивается позиция (0, 0). В разметке не сложно проследить порядок добавления элементов на экран сверху вниз:
Если кто-то обратил внимание, то позицию мы указали только одному виджету:
Каждому виджету в Kivy помимо конкретных координат (x, y) можно указать подсказку позиции:
Так вот, нижнее фоновое изображение…
… благодаря виджету FitImage (библиотека KivyMD), автоматически растягивается на все выделенное ему пространство с сохранением пропорций изображения:
По умолчанию каждому виджету и лайоуту в Kivy предоставляется 100 % пространства, если не указанно иное. Например, если вы захотите добавить на экран одну кнопку, вы, очевидно сделаете следующее:
И получите результат:
Кнопка заняла 100 % пространства. Чтобы разместить кнопку по центру экрана, нужно, во-первых, задать ей необходимый размер и, во-вторых, указать, где она будет находится:
Теперь картина изменилась:
Также можно указать свойство size_hint, от 0 до 1, (эквивалент 0-100%), то есть, подсказка размера:
Или тоже самое, но подсказка ширины (size_hint_x):
MDToolbar имеет высоту в 56dp, не может занимать все пространство, и если ему не подсказать, что его место сверху, то он автоматически прилипнет к нижней части экрана:
Список карточек — OrderProductLayout (о нем мы поговорим ниже) — это ScrollView с элементами MDCard и он занимает всю высоту экрана, но благодаря padding (значения отступов в лайоутах) кажется, что он находится чуть выше центра экрана. Ну а MDBottomAppBar по умолчанию кидает якорь к нижней границе экрана. Поэтому только MDToolbar мы указали, где его место.
Теперь давайте посмотрим, что представляет из себя виджет OrderProductLayout:
Как видим, это четыре карточки, вложенные в ScrillView. В отличие от родительского экрана, который унаследован от FloatLayout, здесь все виджеты читаются сверху вниз.
Это очень удобно, поскольку прослеживается четкая иерархия виджетов, древовидная структура и с одного взгляда понятно, какой виджет/контролл какому лайоуту принадлежит. В Kivy наиболее частым используемым лайоутом является BoxLayout — коробка, которая позволяет размещать в себе виджеты по вертикали либо по горизонтали (по умолчанию — последнее):
Более наглядно это видно из следующей схемы, где используется BoxLayout горизонтальной ориентации:
Мы запретили BoxLayout использовать 100% пространства — size_hint_y: None и сказали — твоя высота будет ровно такой, какой будет высота самого высокого элемента, вложенного в тебя — height: self.minimum_height.
Если бы мы захотели использовать вертикальную прокрутку списка, нам нужно было бы изменить GridLayout следующим образом:
Заменить строки (rows) на столбцы (cols) и указать в minimum не ширину, а высоту:
Следующие карты — выбор цвета и размера (они практически идентичны):
Отличительной особенностью языка разметки Kv Language является не только четкая структура виджетов, но и то, что этот язык поддерживает некоторые возможности языка Python. А именно: вызов методов, создание/изменение переменных, логические, I/O и математические операции…
Вычисление значения value, объявленного в Label…
… происходит непосредственно в самой разметке:
И я никогда не поверю, что вот это (код Flutter)…
… логичнее и читабельнее кода Kv Language:
Вчера меня спрашивали, как у Kivy обстоят дела со средой разработки, есть ли автокомплиты, хотрелоад и прочие прелести? С автокомплитами все отлично, если пользоваться PyCharm:
Насчет хотрелоад… Python — интерпретируемый язык. Kivy использует Python. Соответственно, чтобы увидеть результат, не нужна компиляция кода, запустил — увидел/протестирвал. Как я уже говорил, Kivy не использует нативные API для рендера UI, поэтому позволяет эмулировать различные модели устройств и платформ с помощью модуля screen. Достаточно запустить ваш проект с нужными параметрами, чтобы на компьютере открылось окно тестируемого приложения так, как если бы оно было запущено на реальном устройстве. Звучит странно, но поскольку Kivy абстрагируется от платформы в отрисовке UI, это позволяет не использовать тяжелые и медленные эмуляторы для тестов. Это касается только UI. Например, тестовое приложение, описываемое в этой статье тестировалось с параметрами -m screen:droid2, portrait, scale=.75.
Слева — запущено на мобильном устройстве, справа — на компьютере:
Ну, и, наконец, финальный результат — запуск на мобильном устройстве…
Единственное, что огорчает, это скорость запуска. У того же Flutter она просто феноменальная!
Надеюсь, был кому-то полезен, до новых встреч!
Как писать простенькие приложения для Android, используя яп Python? [закрыт]
Хотите улучшить этот вопрос? Добавьте больше подробностей и уточните проблему, отредактировав это сообщение.
Тратить огромное кол-во времени на изучение java, для написания простеньких бот-программ считаю не лучшим решением
1 ответ 1
Python-for-android Прежде всего давайте посмотрим на то, с помощью чего Python получает возможность работать под Android — инструмент, названный, как ни странно, python-for-android. Его основная функция состоит в том, чтобы создать дистрибутив — папку проекта, содержащую все необходимое для запуска вашего приложения. А точнее, сам интерпретатор, Kivy и библиотеки, от которых он зависит: Pygame, SDL и несколько других. Также дистрибутив включает в себя загрузчик Java, отображающий OpenGL и выступающий в качестве посредника между Kivy и операционной системой. Затем вы добавляете ко всему этому свои скрипты, настройки вроде иконки и имени, компилируете с помощью Android NDK и вуаля — APK с вашим приложением готов!
И это всего лишь базовая процедура, на самом деле сгенерированный пакетный файл может включать (и включает) в себя гораздо больше. Вместе со всем прочим в APK вшивается большая часть стандартной библиотеки, а любой сторонний модуль, написанный на Python, может быть легко добавлен — все так же, как и при разработке десктоп-приложений. Добавка модулей с компилируемыми компонентами тоже не вызывает трудностей, необходимо лишь указать, как их нужно собирать. Как правило, это не представляет собой ничего сложного, достаточно лишь поставить пару галочек перед запуском процедуры сборки, хотя в редких отдельных случаях могут понадобиться дополнительные действия. Python-for-android уже включает в себя указания для компиляции таких популярных модулей, как: numpy, sqlite3, twisted и даже django!
Вышеописанные принципы лишь в общих словах объясняют, как работает python-for-android. В любой момент вы можете получить больше информации на данную тему, заглянув в документацию Kivy. Я рекомендую вам Buildozer — надстройку для python-for-android, предоставляющую собой удобный интерфейс и автоматическое разрешение некоторых зависимостей. Мы стараемся сделать так, чтобы написанная выше цепочка действий использовалась не только в Kivy, но и в других проектах. Основной процесс сборки останется таким же, но нужда в загрузчике Java отпадет, так как он необходим только для поддержки некоторых специфичных нужд фреймворка.
Обращение к Android API с помощью PyJNIus Взаимодействие с Android API: получение информации с сенсоров, создание уведомлений, вибрация, пауза и перезапуск, да что угодно — важная часть вашего приложения. Kivy за вас позаботится об основном, но многими вещами вы захотите управлять сами. Для этого создан PyJNIus — инструмент, автоматически оборачивающий код на Java в интерфейс Python.
В качестве простого примера приведем программу, которая заставит телефон вибрировать на протяжении 10 секунд:
Если вы знакомы с Android API, то без труда заметите, что код выше очень похож на аналогичный на Java — PyJNIus просто позволяет нам обращаться к тому же API, но прямо из Python. Большая часть Android API может быть вызвана подобным образом, что позволяет достичь того же функционала, что и при разработке на Java.
Главный минус PyJNIus в том, что он требует неплохого понимания структуры Android API, а код выходит громоздким, хотя его эквивалент на Java выглядит точно так же. Для решения этой проблемы Kivy включает в себя Plyer.
Plyer: кроссплатформенное API для платформоспецифичных задач Проект Plyer ставит себе цель создать простой «питоничный» интерфейс для функций, которые присутствуют на большинстве платформ. Например, код выше легким движением руки превращается в…
Более того, написанный код попытается выполнить свою задачу на всех поддерживаемых Plyer платформах — на данный момент это: Android, iOS, Linux, Windows и OS X (для iOS также существует аналог PyJNIus, называемая PyOBJus). На самом деле, вибрация — не самый лучший пример, потому что сейчас она реализована только для Android, но такие функции как проверка уровня заряда батареи:
— работают как в десктопных, так и в мобильных приложениях, а получение данных с компаса/гироскопа и отправка SMS без проблем реализуются на Android и iOS.
Plyer находится на начальной стадии развития, так что любая помощь в разработке приветствуется. Также, мы участвуем с ним в Google Summer of Code в этом году.
Не только ради Kivy Все вышеперечисленные инструменты были разработаны для нашего фреймворка, но на самом деле они больше предназначены для разработки под Python в целом. В Plyer мы специально избегаем какой-либо зависимости от Kivy, а PyJNIus нужен лишь для доступа к Android JNI. Искренне надеемся, что эти инструменты станут полезны для любого, кто пишет на Python под Android. Вы уже можете попробовать PyJNIus, используя QPython. Python-for-android больше завязан на взаимодействии с Kivy, но мы будем рады обсудить этот вопрос.
Многое можно реализовать при разработке на Android с помощью Python, несмотря на все различия с Java, которая предназначена для этого, но эти возможности могут быть расширены еще больше в ближайшем будущем. И если вы заинтересовались описанными выше проектами, то самое время присоединиться к нашей команде!
Как разрабатывать на Python под Android
Рассказывает Александр Тейлор, разработчик проекта Kivy
В последнее время появляется большое количество ресурсов по разработке на Python под Android. Все чаще упоминается предназначенный для этой задачи фреймворк Kivy (и его ответвления), ведь он является одним из самых проверенных временем и надежных проектов в этой области. Тем не менее, одну важную деталь незаслуженно обделяют вниманием — что вообще мы сможем делать после того, как Python станет запускаться на устройстве? Есть ли какие-то ограничения? Все ли библиотеки можно подключать? Возможно ли делать все то же, что и при написании приложения на Java? Данные вопросы волнуют многих, и они рассматриваются и решаются в рамках проекта Kivy. В этой статье я постараюсь рассмотреть наиболее интересные и важные детали.
Python-for-android
Прежде всего давайте посмотрим на то, с помощью чего Python получает возможность работать под Android — инструмент, названный, как ни странно, python-for-android. Его основная функция состоит в том, чтобы создать дистрибутив — папку проекта, содержащую все необходимое для запуска вашего приложения. А точнее, сам интерпретатор, Kivy и библиотеки, от которых он зависит: Pygame, SDL и несколько других. Также дистрибутив включает в себя загрузчик Java, отображающий OpenGL и выступающий в качестве посредника между Kivy и операционной системой. Затем вы добавляете ко всему этому свои скрипты, настройки вроде иконки и имени, компилируете с помощью Android NDK и вуаля — APK с вашим приложением готов!
И это всего лишь базовая процедура, на самом деле сгенерированный пакетный файл может включать (и включает) в себя гораздо больше. Вместе со всем прочим в APK вшивается большая часть стандартной библиотеки, а любой сторонний модуль, написанный на Python, может быть легко добавлен — все так же, как и при разработке десктоп-приложений. Добавка модулей с компилируемыми компонентами тоже не вызывает трудностей, необходимо лишь указать, как их нужно собирать. Как правило, это не представляет собой ничего сложного, достаточно лишь поставить пару галочек перед запуском процедуры сборки, хотя в редких отдельных случаях могут понадобиться дополнительные действия. Python-for-android уже включает в себя указания для компиляции таких популярных модулей, как: numpy, sqlite3, twisted и даже django!
Вышеописанные принципы лишь в общих словах объясняют, как работает python-for-android. В любой момент вы можете получить больше информации на данную тему, заглянув в документацию Kivy. Я рекомендую вам Buildozer — надстройку для python-for-android, предоставляющую собой удобный интерфейс и автоматическое разрешение некоторых зависимостей. Мы стараемся сделать так, чтобы написанная выше цепочка действий использовалась не только в Kivy, но и в других проектах. Основной процесс сборки останется таким же, но нужда в загрузчике Java отпадет, так как он необходим только для поддержки некоторых специфичных нужд фреймворка.
Обращение к Android API с помощью PyJNIus
Взаимодействие с Android API: получение информации с сенсоров, создание уведомлений, вибрация, пауза и перезапуск, да что угодно — важная часть вашего приложения. Kivy за вас позаботится об основном, но многими вещами вы захотите управлять сами. Для этого создан PyJNIus — инструмент, автоматически оборачивающий код на Java в интерфейс Python.
В качестве простого примера приведем программу, которая заставит телефон вибрировать на протяжении 10 секунд:
Если вы знакомы с Android API, то без труда заметите, что код выше очень похож на аналогичный на Java — PyJNIus просто позволяет нам обращаться к тому же API, но прямо из Python. Большая часть Android API может быть вызвана подобным образом, что позволяет достичь того же функционала, что и при разработке на Java.
Главный минус PyJNIus в том, что он требует неплохого понимания структуры Android API, а код выходит громоздким, хотя его эквивалент на Java выглядит точно так же. Для решения этой проблемы Kivy включает в себя Plyer.
Plyer: кроссплатформенное API для платформоспецифичных задач
Проект Plyer ставит себе цель создать простой «питоничный» интерфейс для функций, которые присутствуют на большинстве платформ. Например, код выше легким движением руки превращается в…
Более того, написанный код попытается выполнить свою задачу на всех поддерживаемых Plyer платформах — на данный момент это: Android, iOS, Linux, Windows и OS X (для iOS также существует аналог PyJNIus, называемая PyOBJus). На самом деле, вибрация — не самый лучший пример, потому что сейчас она реализована только для Android, но такие функции как проверка уровня заряда батареи:
— работают как в десктопных, так и в мобильных приложениях, а получение данных с компаса/гироскопа и отправка SMS без проблем реализуются на Android и iOS.
Plyer находится на начальной стадии развития, так что любая помощь в разработке приветствуется. Также, мы участвуем с ним в Google Summer of Code в этом году.
Не только ради Kivy
Все вышеперечисленные инструменты были разработаны для нашего фреймворка, но на самом деле они больше предназначены для разработки под Python в целом. В Plyer мы специально избегаем какой-либо зависимости от Kivy, а PyJNIus нужен лишь для доступа к Android JNI. Искренне надеемся, что эти инструменты станут полезны для любого, кто пишет на Python под Android. Вы уже можете попробовать PyJNIus, используя QPython. Python-for-android больше завязан на взаимодействии с Kivy, но мы будем рады обсудить этот вопрос.
Многое можно реализовать при разработке на Android с помощью Python, несмотря на все различия с Java, которая предназначена для этого, но эти возможности могут быть расширены еще больше в ближайшем будущем. И если вы заинтересовались описанными выше проектами, то самое время присоединиться к нашей команде!
Разработка игры под Android на Python на базе Kivy. От А до Я: подводные камни и неочевидные решения. Часть 1
Некоторое время тому назад я решил попробовать написать что-то на Python под Android. Такой странный для многих выбор обусловлен тем, что я люблю Python и люблю Android, а ещё люблю делать необычное (ну хорошо, не самое обычное). В качестве фреймворка был выбран Kivy — фактически, безальтернативный вариант, но он мне очень понравился. Однако, по нему не так уж много информации (нет, документация отличная, но иногда её недостаточно), особенно на русском языке, а некоторые вещи хоть и можно реализовать, но их то ли никто раньше не делал, то ли не счёл нужным поделиться информацией. Ну а я счёл 🙂 И этот пост тому результатом.
Под катом я расскажу обо всех этапах разработки, о том, как развивалась простая идея и как для этого приходилось искать новые возможности, о возникших подводных камнях и багах, о неочевидных решениях и устаревшей документации 🙂 Цель — описать в одном тексте основные пункты, чтобы человеку, решившему написать что-то немного сложнее игры Pong из официального туториала, не приходилось перерывать официальный форум поддержки и StackOverflow и тратить часы на то, что делается за пару минут, если знаешь, как.
0. Если вы впервые слышите о Kivy.
… то всё зависит от того, любите ли вы Python и Android, и интересно ли вам в этом разобраться. Если нет — проще забить 🙂 А если да, то начать нужно с официальной документации, гайдов, и уже упомянутого официального туториала по игре Pong — это даст базовое представление о фреймворке и его возможностях. Я же не буду останавливаться на столь тривиальных вещах (тем более, для понимания базовых принципов туториал отлично подходит) и сразу пойду дальше. Будем считать, что это было вступление 🙂
1. Немного о моей игре
Для начала нужна была идея. Мне хотелось что-то достаточно простое, чтобы оценить возможности фреймворка, но и достаточно интересное и оригинальное, чтобы не программировать ради программирования (это здорово, но когда это не единственная цель — это ещё лучше). Я неплохо проектирую интерфейсы, но не умею рисовать, поэтому игра должна была быть простая графически, или вообще текстовая. И тут так уж сложилось, что у меня есть заброшенный сайт с цитатами, с которого я когда-то начинал свой путь в web-разработке (я о нём даже писал на Хабре много лет назад). Поэтому идея возникла такая: игра-викторина «Угадай цитату». В русскоязычном Google Play ничего подобного не было, а в англоязычном была пара поделок низкого качества с сотней скачиваний.
Почти сразу же стало понятно, что просто так отгадывать цитату за цитатой — скучно. Так появились первые «фишки», которые, в итоге, и определили итоговую игру. В первую очередь это были тематические пакеты (то есть пакеты цитат, объединённые одной темой или автором) и баллы (которые начисляются за отгадывание цитат и прохождение пакетов, и тратятся на подсказки и разблокировку новых тем), а также статистика, достижения и избранное.
Так всё начиналось (кликабельно):
Ну ладно, ладно, больше не буду показывать такой ужас 🙂 Кстати, вот так оно выглядит сейчас (тоже кликабельно, скрины взяты с Google Play):
Первые проблемы начались с первого же экрана…
2. Kivy тормоз или я что-то делаю не так?
Один мой друг любит отвечать на такие вопросы «да» 🙂 На самом деле, некоторые вещи в Kivy действительно работают медленно, например, создание виджетов. Но это не значит, что это дело нельзя оптимизировать. Об этом я и расскажу.
Так как цитаты и темы хранятся в БД, то, само собой, кнопки с пакетами генерируются динамически. И вот тут-то я обнаружил, что происходит это очень медленно: примерно полсекунды на список из 20 кнопок. Возможно, это и не очень много при загрузке приложения, но при переходе на главный экран из других внутренних экранов приложения — непозволительно много. Здесь стоит отметить, что кнопка к тому моменту уже представляла собой, на самом деле, набор из нескольких элементов, визуально составляющих одну кнопку:
Первым моим побуждением было тем или иным образом закешировать их, и, действительно, опыт показал, что если создать все виджеты заранее, и сохранить их как свойство объекта StartScreen, то всё (кроме первой генерации) работает достаточно быстро. Однако же, данные в кнопках нужно периодически обновлять (хотя бы то же количество отгаданных цитат). Да и загрузку новых пакетов я уже тогда планировал. Конечно, не проблема реализовать и это, но я решил не изобретать велосипед и подумать.
Сначала стоило убедиться, что проблема именно в создании виджетов, поэтому я за несколько минут набросал простенькое приложение на два экрана, в каждом из которых генерировался набор строк из лейбла и чекбокса количеством 50 шт. 🙂
Запустил на своём стареньком Moto G (gen3) и получил:
И далее в том же духе. Поиск по этому вопросу ничего не дал, поэтому я обратился к разработчикам. И получил ответ: «Создание виджетов относительно медленное, особенно в зависимости от того, что они содержат. Для создания больших списков лучше использовать RecycleView». Здесь хочу пояснить, почему я вообще описываю этот момент, ведь описание RecycleView есть в документации. Да, действительно, есть, но мало кто способен изучить и запомнить всю документацию перед тем, как начнёт разработку, и найти нужный инструмент бывает непросто, особенно если он нигде не описан в контексте решения конкретной проблемы. Теперь же он описан 🙂
Более чем в 100 раз быстрее. Впечатляет, не правда ли?
В завершение следует упомянуть, что RecycleView — не панацея. Он не подходит, если размер элемента зависит от содержимого (например, Label, размер которого меняется в зависимости от количества текста).
3. Сервисы. Автозапуск и перезапуск
Следующая проблема, с которой я столкнулся, не поддавалась решению так долго, что я уже малодушно подумывал счесть данный фреймворк непригодным и забить 🙂 Проблема была с сервисами (в Android так называется процессы, выполняющиеся в фоновом режиме). Создать сервис не так уж и сложно — немного сбивает с толку устаревшая документация, но и только. Однако, в большинстве случаев, много ли толку от сервиса, который, во-первых, не запускается автоматически при загрузке телефона, а во-вторых, не перезапускается, если «выбросить» приложение свайпом из диспетчера задач? По-моему, нет.
На тот момент по этой теме была всего лишь одна статья в официальной wiki, но она, хоть и называлась «Starting Kivy service on bootup», на самом деле всего лишь рассказывала, как при загрузке телефона запустить приложение, но не его сервис (да, такое тоже бывает полезно, но значительно реже, как по мне). Ту статью я, в итоге, переписал, а здесь расскажу подробности.
Допустим, у нас есть примитивный сервис, который всего-то и делает, что периодически выводит в лог строку (этим мы заранее исключаем баги, которые могут возникать из-за особенностей самого сервиса).
Из приложения мы запускаем его методом основного класса при помощи PyJnius:
Если APK собран правильно, при запуске приложения сервис будет стартовать, но этого недостаточно.
Для начала, попробуем сделать так, чтобы он перезапускался при остановке приложения (например, при снятии его из диспетчера задач). Конечно, можно было бы использовать startForeground, но это уже не совсем фоновое выполнение задачи 🙂 Для него потребуется, как минимум, уведомление — это не всегда подходит. В данном случае идеально подходит флаг START_STICKY, но мы же пишем на Python, что делает задачу не столь тривиальной — по крайней мере, при помощи PyJnius она уже не решается.
Ура, сервис рестартится. Всё? Конечно, нет 🙂 Потому что он тут же валится с ошибкой:
Проблема в функции onStartCommand(Intent intent, int flags, int startId), поскольку после перезапуска intent у нас null. Что ж, перепишем и её:
Проблема в том, что функция nativeStart() не получает нужных Extras. К сожалению, два из них мне пришлось захардкодить. В итоге выглядит это так:
Перейдём к автозапуску сервиса при запуске телефона. После предыдущей проблемы это будет уже проще. (На самом деле же всё было наоборот — я очень долго не мог понять, что именно нужно добавить, поскольку информации об этом не было вообще нигде, и сами разработчики тоже не знали, как решить данную задачу. И только разобравшись параллельно с вопросом перезапуска, я понял, что нужно сделать.)
Для начала понадобится разрешение RECEIVE_BOOT_COMPLETED — это просто. А затем — BroadcastReceiver, его придётся добавить в AndroidManifest вручную, но это тоже не проблема. Проблема в том, что в нём писать 🙂
Решение для запуска приложения (не сервиса) выглядит так:
Сначала я попытался просто переписать его для сервиса:
Думаю, вам уже понятно, что проблема в тех самых Extras. Мне же тогда об этом было узнать неоткуда. Но не буду тянуть, рабочий код выглядит так:
Локализация и мультиязычность
В целом, для локализации можно использовать gettext, или же поступить ещё проще — создать папку lang, в ней по файлу на каждый язык (например, en.py и ru.py), определить там все слова и фразы в виде переменных/констант, и далее подключить нужный модуль. Примерно так:
Статическая переменная использована для того, чтобы языковые константы было удобно использовать в kv-файле: