Ресурсы в Compose Multiplatform
#compose
Не секрет, что ни один из проектов не обходится без ресурсов, а управление ими становится только сложнее с ростом проекта. Ну и становится сложнее, когда проект написан на несколько платформ сразу.
Неплохая обзорная статья, где описываются основные изменения работы с ресурсами после свежего релиза Compose Multiplatform 1.6.0-beta01.
В целом, стало всё чуть удобнее, но буду рад, если поделитесь практическими примерами оптимизации ресурсов в подобных приложениях.
#compose
Не секрет, что ни один из проектов не обходится без ресурсов, а управление ими становится только сложнее с ростом проекта. Ну и становится сложнее, когда проект написан на несколько платформ сразу.
Неплохая обзорная статья, где описываются основные изменения работы с ресурсами после свежего релиза Compose Multiplatform 1.6.0-beta01.
В целом, стало всё чуть удобнее, но буду рад, если поделитесь практическими примерами оптимизации ресурсов в подобных приложениях.
Device streaming
#androidstudio
О, тут в Android Studio Jellyfish подвезли Device streaming: фича, которая позволяет тестировать своё приложение на различных девайсах, которые находятся в дата центрах Google.
Прикольная фича, стоит обратить внимание, особенно когда выходит свежая версия Android, а на ваши устройства она ещё не прилетела. Да и специфические устройства, типа Fold тоже не каждый хочет себе покупать.
Работает аналогично обычному подключению устройства, и фича бесплатна, пока находится в alpha. Дальше всё за монету и будет учитываться время подключения к устройству.
Все детали можно почитать тут.
#androidstudio
О, тут в Android Studio Jellyfish подвезли Device streaming: фича, которая позволяет тестировать своё приложение на различных девайсах, которые находятся в дата центрах Google.
Прикольная фича, стоит обратить внимание, особенно когда выходит свежая версия Android, а на ваши устройства она ещё не прилетела. Да и специфические устройства, типа Fold тоже не каждый хочет себе покупать.
Работает аналогично обычному подключению устройства, и фича бесплатна, пока находится в alpha. Дальше всё за монету и будет учитываться время подключения к устройству.
Все детали можно почитать тут.
RTL адаптация в Android
#android
Хорошая статья, где описывается опыт поддержки RTL-языков в Android, в том числе и на Compose.
Для тех, кто не в теме. RTL (right-to-left) — это чтение справа-налево, которое встречается в языках ближнего востока, например, арабский. LTR (left-to-right) — привычное нам чтение слева-направо.
В Android довольно неплохо поддерживаются RTL-языки, начиная с API 17, но тем не менее — есть масса кейсов, на которые стоит посмотреть при тестировании.
Был опыт адаптации приложения под RTL-языки? Вдруг вы настолько круты, что адаптировали свой pet-проект, кто знает, расскажите в комментариях.🇦🇪
#android
Хорошая статья, где описывается опыт поддержки RTL-языков в Android, в том числе и на Compose.
Для тех, кто не в теме. RTL (right-to-left) — это чтение справа-налево, которое встречается в языках ближнего востока, например, арабский. LTR (left-to-right) — привычное нам чтение слева-направо.
В Android довольно неплохо поддерживаются RTL-языки, начиная с API 17, но тем не менее — есть масса кейсов, на которые стоит посмотреть при тестировании.
Был опыт адаптации приложения под RTL-языки? Вдруг вы настолько круты, что адаптировали свой pet-проект, кто знает, расскажите в комментариях.
Please open Telegram to view this post
VIEW IN TELEGRAM
Кастомный Android Lint
#androidstudio
Интересное решение довольно популярной проблемы. На больших проектах, где уже есть сформированная кодовая база, существует целый набор кастомных функций, о которых ещё не знают вновь пришедшие разработчики.
Решить эту проблему предлагается в этой статье при помощи кастомного Android Lint Rule. В ней, описывается кейс, когда мы хотим использовать кастомную функцию вместо elvis-оператора.
Вероятно, для вашего проекта это не совсем применимо, но статья полезна прежде всего как неплохой старт в написании кастомных правил для Lint. Это прям топ инструмент, который не то, чтобы обширно используется.🥸
#androidstudio
Интересное решение довольно популярной проблемы. На больших проектах, где уже есть сформированная кодовая база, существует целый набор кастомных функций, о которых ещё не знают вновь пришедшие разработчики.
Решить эту проблему предлагается в этой статье при помощи кастомного Android Lint Rule. В ней, описывается кейс, когда мы хотим использовать кастомную функцию вместо elvis-оператора.
Вероятно, для вашего проекта это не совсем применимо, но статья полезна прежде всего как неплохой старт в написании кастомных правил для Lint. Это прям топ инструмент, который не то, чтобы обширно используется.
Please open Telegram to view this post
VIEW IN TELEGRAM
Getting to Know Koin Annotations
#koin #kmm
Полезная статья-справочник по аннотациям в моём любимом DI-фреймворке — Koin.
Тут и про Koin DSL, и про Constructor DSL, и про аннотации. А ещё — как всё же проверять зависимости в compile time.
Кстати, Koin отлично себя показывает в мультиплатформе.😇
Использовали в своих проектах? Как вам?
#koin #kmm
Полезная статья-справочник по аннотациям в моём любимом DI-фреймворке — Koin.
Тут и про Koin DSL, и про Constructor DSL, и про аннотации. А ещё — как всё же проверять зависимости в compile time.
Кстати, Koin отлично себя показывает в мультиплатформе.
Использовали в своих проектах? Как вам?
Please open Telegram to view this post
VIEW IN TELEGRAM
Дизайн система Android через Figma API
#design #android #ci
С ростом проекта количество ресурсов, которое появляется в приложении очень сильно растёт, и управлять ими становится всё сложнее. Со временем многие команды приходят к тому, чтобы настроить и использовать свою дизайн-систему.
В проектах, где я работал — мы всегда приходили к какой-то дизайн системе. Иногда не совсем удачно, но чаще это очень сильно экономило время и ресурсы всех команд.
Правда, никогда не получалось сделать обновление ресурсов через CI.
Если вы хотите добавить ещё больше автоматизации в ваш проект — можно взять за основу эту статью, где ребята рассказывают свой путь, чтобы подружить Figma и обновление некоторых элементов дизайн-системы.
Тут и небольшой обзор текущих решений, и то, как всё это дело работает в xml и Compose.🥸
#design #android #ci
С ростом проекта количество ресурсов, которое появляется в приложении очень сильно растёт, и управлять ими становится всё сложнее. Со временем многие команды приходят к тому, чтобы настроить и использовать свою дизайн-систему.
В проектах, где я работал — мы всегда приходили к какой-то дизайн системе. Иногда не совсем удачно, но чаще это очень сильно экономило время и ресурсы всех команд.
Правда, никогда не получалось сделать обновление ресурсов через CI.
Если вы хотите добавить ещё больше автоматизации в ваш проект — можно взять за основу эту статью, где ребята рассказывают свой путь, чтобы подружить Figma и обновление некоторых элементов дизайн-системы.
Тут и небольшой обзор текущих решений, и то, как всё это дело работает в xml и Compose.
Please open Telegram to view this post
VIEW IN TELEGRAM
State in your Kotlin apps
#kotlin #android
Архитектуры с Unidirectional Data Flow сейчас очень популярны в большинстве современных приложений: это отличный подход, который позволяет избежать ошибок при обновлении экрана, да и разрабатывать с этим подходом удобнее, особенно большие приложения.
К сожалению, подход не избавляет от багов на 100%, да и многие разработчики используют его не совсем корректно.
Чтобы избежать некоторых из багов, вот отличная статья, где указываются на некоторые проблемы и способы их решения. Одинаково будет полезно как новичкам, так и опытным разработчикам, ведь от ошибок не застрахованы даже профи.
Кстати, автор статьи подписан на канал, так что свои вопросы по статье можете задать в комментариях.🤓
#kotlin #android
Архитектуры с Unidirectional Data Flow сейчас очень популярны в большинстве современных приложений: это отличный подход, который позволяет избежать ошибок при обновлении экрана, да и разрабатывать с этим подходом удобнее, особенно большие приложения.
К сожалению, подход не избавляет от багов на 100%, да и многие разработчики используют его не совсем корректно.
Чтобы избежать некоторых из багов, вот отличная статья, где указываются на некоторые проблемы и способы их решения. Одинаково будет полезно как новичкам, так и опытным разработчикам, ведь от ошибок не застрахованы даже профи.
Кстати, автор статьи подписан на канал, так что свои вопросы по статье можете задать в комментариях.
Please open Telegram to view this post
VIEW IN TELEGRAM
Sync speedup в Gradle
#gradle
Вечная тема для Android-разработчиков — уменьшение времени сборки и ускорение Gradle.
Вот вам ещё одна улучшайка в копилку, сам пока не пробовал, но выглядит любопытно.
Автор обратил внимание на добавляемые репозитории в проект и решил посмотреть на то, куда уходит время при синке. Выяснилось, что много времени уходит на попытки получения зависимостей в тех репозиториях, где их нет, из-за чего sync увеличивается по времени.
Недолгий research показал, что можно добавить параметры exclusiveContent и content для каждого из репозитория, указывая там группы репозиториев.
Ещё интересный фикс — это настройка порядка репозиториев, оказывается он тоже влияет на скорость синка. Может сгодиться как быстрый фикс.
У автора получилось уменьшить время sync с почти 6 минут до 3 минут 17 секунд, что выглядит крайне круто.🔥
#gradle
Вечная тема для Android-разработчиков — уменьшение времени сборки и ускорение Gradle.
Вот вам ещё одна улучшайка в копилку, сам пока не пробовал, но выглядит любопытно.
Автор обратил внимание на добавляемые репозитории в проект и решил посмотреть на то, куда уходит время при синке. Выяснилось, что много времени уходит на попытки получения зависимостей в тех репозиториях, где их нет, из-за чего sync увеличивается по времени.
Недолгий research показал, что можно добавить параметры exclusiveContent и content для каждого из репозитория, указывая там группы репозиториев.
Ещё интересный фикс — это настройка порядка репозиториев, оказывается он тоже влияет на скорость синка. Может сгодиться как быстрый фикс.
У автора получилось уменьшить время sync с почти 6 минут до 3 минут 17 секунд, что выглядит крайне круто.
Please open Telegram to view this post
VIEW IN TELEGRAM
Practical Optimizations
#android #optimization
Для всех, кто любит низкоуровневые оптимизации и прочий хардкод — прекрасный доклад от Romain Guy, где он описывает целый набор оптимизаций, которые они сделали в Compose.
В целом, будет полезно всем разработчикам: можно научиться чуть лучше читать bytecode как минимум. А как максимум — сделаете крутую оптимизацию в своём проекте.
А вот тут почти то же самое, но в цикле статей, если вам так удобнее.
#android #optimization
Для всех, кто любит низкоуровневые оптимизации и прочий хардкод — прекрасный доклад от Romain Guy, где он описывает целый набор оптимизаций, которые они сделали в Compose.
В целом, будет полезно всем разработчикам: можно научиться чуть лучше читать bytecode как минимум. А как максимум — сделаете крутую оптимизацию в своём проекте.
А вот тут почти то же самое, но в цикле статей, если вам так удобнее.
Kotlin: An Illustrated Guide
#kotlin
Сайт для новичков, который стоит добавить в закладки и опытным разработчикам — Dave Leeds on Kotlin.
Мне кажется, один из самых понятных и удобных гайдов по Kotlin, который я когда-либо видел. Примеры, забавные иллюстрации, простые примеры кода. Даже если вы знаете все темы — имеет смысл перечитать, ведь не всегда мы можем объяснить всё на пальцах так, чтобы поняла ваша бабушка .
А если вы новичок — можете смело начать изучение с этого гайда.
Последняя глава про Generic, а скоро ожидается про Coroutine.
#kotlin
Сайт для новичков, который стоит добавить в закладки и опытным разработчикам — Dave Leeds on Kotlin.
Мне кажется, один из самых понятных и удобных гайдов по Kotlin, который я когда-либо видел. Примеры, забавные иллюстрации, простые примеры кода. Даже если вы знаете все темы — имеет смысл перечитать, ведь не всегда мы можем объяснить всё на пальцах
А если вы новичок — можете смело начать изучение с этого гайда.
Последняя глава про Generic, а скоро ожидается про Coroutine.
Koala: New Terminal
#androidstudio
Я постоянный пользователь Beta-версий Android Studio. Мне почему-то везёт, и я не натыкаюсь на проблемы, которые мешают работе, поэтому всегда использую их вместо релизной версии.
И вот недавно в Android Studio Koala протестировал новый терминал. Выглядит гораздо удобнее, чем привычный нам. Поэтому спешу мотивировать вас использовать его как можно быстрее.
Если IDE не предложит попробовать его самостоятельно, то можно включить его в Settings/Preferences | Tools | Terminal | Enable New Terminal.
С визуальной точки зрения всё стало значительно симпатичнее, а что самое главное — теперь команды разделяются по блокам и по ним можно быстро перемещаться.🔥
В повседневной работе это невероятно облегчает навигацию по огромной простыне списка.
Ещё одной киллер-фичей является автодополнение, удобная история команд, да и что говорить — цветовая тема и палитра.
В общем, как только обновитесь — обязательно включайте, ведь у вас появится ещё один удобный инструмент.
Тут можно почитать подробнее про все фичи, а также посмотреть на то, как всё выглядит.
Пробовали? Как вам?
#androidstudio
Я постоянный пользователь Beta-версий Android Studio. Мне почему-то везёт, и я не натыкаюсь на проблемы, которые мешают работе, поэтому всегда использую их вместо релизной версии.
И вот недавно в Android Studio Koala протестировал новый терминал. Выглядит гораздо удобнее, чем привычный нам. Поэтому спешу мотивировать вас использовать его как можно быстрее.
Если IDE не предложит попробовать его самостоятельно, то можно включить его в Settings/Preferences | Tools | Terminal | Enable New Terminal.
С визуальной точки зрения всё стало значительно симпатичнее, а что самое главное — теперь команды разделяются по блокам и по ним можно быстро перемещаться.
В повседневной работе это невероятно облегчает навигацию по огромной простыне списка.
Ещё одной киллер-фичей является автодополнение, удобная история команд, да и что говорить — цветовая тема и палитра.
В общем, как только обновитесь — обязательно включайте, ведь у вас появится ещё один удобный инструмент.
Тут можно почитать подробнее про все фичи, а также посмотреть на то, как всё выглядит.
Пробовали? Как вам?
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Android Good Reads (Anton Kondratiuk)
О создании Preview в Jetpack Compose
Как вы подкладываете и обновляете данные для
👉 Хардкодить данные напрямую
👉 Класть все данные в обьект и подменять в процессе подстановки. А более аккуратный способ — это воспользоваться
👉 Написать полноценный отдельный фабричный метод для описания состояния
👉 Использование существующего state holder
У нас в команде решили для каждого UI-класса определять несколько
Как вы подкладываете и обновляете данные для
@Preview
? В статье предлагается:👉 Хардкодить данные напрямую
👉 Класть все данные в обьект и подменять в процессе подстановки. А более аккуратный способ — это воспользоваться
PreviewParameterProvider
(Хорошо описано тут)👉 Написать полноценный отдельный фабричный метод для описания состояния
@Preview
. Мне кажется что это оверинжениринг, только если вы не всецело полагаетесь на превью в работе👉 Использование существующего state holder
У нас в команде решили для каждого UI-класса определять несколько
mock()
функций с основными кейсами. В итоге у нас есть базовые превью, а при переиспользовании всегда видны возможные коллизии на основных кейсах.Dladukedev
The Many Approaches to Providing @Preview data in Jetpack Compose
Jetpack Compose Previews make for faster development and prototyping but the problem of providing data to the component has many solutions. Here is a review of those different solutions, how they might be applied in a given project, and the pros and cons…
So You Think You Know Git
#git
В начале этой недели вдохновился видео про Git и решил поделиться им с вами.
Во всех командах, где я работал использовался Git и его знание даже не обговаривалось. В большинстве случаев хватает использования базовых сценариев и команд: типа push, pull, работа с git flow и т.д.
Однако, Git очень мощный инструмент, и тут есть невероятное количество команд, которые повышают удобство работы в команде. Вот о многих подобных командах можно узнать из видео.
Кто знает, может быть парочку из них и приживутся у вас в команде. А если и не приживутся — в любом случае где-нибудь в компании разработчиков можете понтануться знанием какой-то редкой фичи из Git🤪
#git
В начале этой недели вдохновился видео про Git и решил поделиться им с вами.
Во всех командах, где я работал использовался Git и его знание даже не обговаривалось. В большинстве случаев хватает использования базовых сценариев и команд: типа push, pull, работа с git flow и т.д.
Однако, Git очень мощный инструмент, и тут есть невероятное количество команд, которые повышают удобство работы в команде. Вот о многих подобных командах можно узнать из видео.
Кто знает, может быть парочку из них и приживутся у вас в команде. А если и не приживутся — в любом случае где-нибудь в компании разработчиков можете понтануться знанием какой-то редкой фичи из Git
Please open Telegram to view this post
VIEW IN TELEGRAM
YouTube
So You Think You Know Git - FOSDEM 2024
Scott Chacon's FOSDEM 2024 talk on Git Tips and Tricks.
Scott talks about:
00:00 - Introduction
01:06 - About Me (well, Scott Chacon)
02:36 - How Well Do You Know Git?
05:09 - Our Agenda
06:25 - Some Helpful Config Stuff
09:42 - Oldies But Goodies
16:22…
Scott talks about:
00:00 - Introduction
01:06 - About Me (well, Scott Chacon)
02:36 - How Well Do You Know Git?
05:09 - Our Agenda
06:25 - Some Helpful Config Stuff
09:42 - Oldies But Goodies
16:22…
Перенос приложения в Google Play
#google
Впервые делал перенос приложения с одного Google Dev аккаунта на другой.
Это может понадобиться по нескольким причинам, но, кажется, основная — это изменение всяких юридических данных компании.
И, как бы страшно это ни звучало — сделать перенос приложения довольно просто. Есть даже официальная дока от Google, как это сделать и которой, в принципе, достаточно.
Если кратко, то вам надо создать, оплатить и верифицировать новый аккаунт, а затем сделать request на перенос из вашего первого аккаунта.
Обязательно посмотрите, что можно перенести, а что нельзя. По сути, перенесётся вся информация, включая описание, отзывы, оценки, сервисы (Firebase тот же). В случае нашего приложения — пришлось заново добавить тестовые группы для скачивания приложения и отправить приглашения для доступа в консоль.
Так что — всё не страшно, вдруг этот пост понадобится вам когда-то в карьере.🤟
Впервые делал перенос приложения с одного Google Dev аккаунта на другой.
Это может понадобиться по нескольким причинам, но, кажется, основная — это изменение всяких юридических данных компании.
И, как бы страшно это ни звучало — сделать перенос приложения довольно просто. Есть даже официальная дока от Google, как это сделать и которой, в принципе, достаточно.
Если кратко, то вам надо создать, оплатить и верифицировать новый аккаунт, а затем сделать request на перенос из вашего первого аккаунта.
Обязательно посмотрите, что можно перенести, а что нельзя. По сути, перенесётся вся информация, включая описание, отзывы, оценки, сервисы (Firebase тот же). В случае нашего приложения — пришлось заново добавить тестовые группы для скачивания приложения и отправить приглашения для доступа в консоль.
Так что — всё не страшно, вдруг этот пост понадобится вам когда-то в карьере.
Please open Telegram to view this post
VIEW IN TELEGRAM
Google
Transfer apps to a different developer account - Play Console Help
If you have apps that you want to transfer to a different Google Play developer account, you can submit a transfer request after reviewing the instructions below. Get your app ready to transfer Step
Maven Central Portal в 2024 году
#gradle
С марта 2024 года публикация своей библиотеки через OSSRH портал больше недоступна, и публикация на Maven Central сейчас работает иначе.
Если вам есть необходимость публикации своей библиотеки — есть свежая инструкцикя, где по шагам описываются все нюансы публикации в текущих реалиях. Вдруг понадобится.
#gradle
С марта 2024 года публикация своей библиотеки через OSSRH портал больше недоступна, и публикация на Maven Central сейчас работает иначе.
Если вам есть необходимость публикации своей библиотеки — есть свежая инструкцикя, где по шагам описываются все нюансы публикации в текущих реалиях. Вдруг понадобится.
Хабр
Как публиковать библиотеку в Maven Central Portal в 2024 году
Англоязычная версия статьи на Medium Начиная с 12 марта 2024 года регистрация на OSSRH портале теперь недоступна. Большинство существующих туториалов в интернете описывают как раз опыт публикации...
Data Object
#kotlin
С недавних пор IDEA (а именно с Kotlin 1.9) начала подчёркивать традиционный object и рекомендует заменить его на странный data object. Что за зверь такой и что он нам даёт? Давайте разберёмся.
При использовании sealed class или sealed interface мы могли добавлять разные стейты внутри его. Они могли быть как data class, так и object. Например:
Однако, если мы захотели бы вывести результат в лог, то с data class все получилось бы хорошо, а вот с object — не очень: мы бы увидели только адреса, например:
Можно было бы обмазаться старым добрым toString() для каждого объекта, но вместо этого — самое время использовать data object, где эта проблема полностью решена.
Хоть обновление и минорное, но заметно добавляет удобства при работе с подобными классами.🔥
#kotlin
С недавних пор IDEA (а именно с Kotlin 1.9) начала подчёркивать традиционный object и рекомендует заменить его на странный data object. Что за зверь такой и что он нам даёт? Давайте разберёмся.
При использовании sealed class или sealed interface мы могли добавлять разные стейты внутри его. Они могли быть как data class, так и object. Например:
sealed interface ProfileScreenState {
data class Success(val username: String): ProfileScreenState
object Error: ProfileScreenState
object Loading: ProfileScreenState
}
Однако, если мы захотели бы вывести результат в лог, то с data class все получилось бы хорошо, а вот с object — не очень: мы бы увидели только адреса, например:
com.dataobjects.example.ProfileScreenState$Loading@6d03e736
Success(username=exampleUser1)
com.dataobjects.example.ProfileScreenState$Error@5fd0d5ae
Можно было бы обмазаться старым добрым toString() для каждого объекта, но вместо этого — самое время использовать data object, где эта проблема полностью решена.
Хоть обновление и минорное, но заметно добавляет удобства при работе с подобными классами.
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Gorshkov Blog (Aleksandr Gorshkov)
Друзья, с Днём программиста! 💻🎉
Знаю, вы тут есть, и сегодня наш профессиональный праздник
Спасибо всем, кто каждый день решает сложные задачи, создаёт инновации и делает этот мир более технологичным. Пусть ваши проекты всегда компилируются без ошибок, а баги исчезают так же быстро, как и появляются! 🚀
Желаем вам вдохновения, новых вызовов и ещё больше успешных решений! Продолжайте менять мир!
P.S. на фото тортик от жены в честь праздника🖤
Знаю, вы тут есть, и сегодня наш профессиональный праздник
Спасибо всем, кто каждый день решает сложные задачи, создаёт инновации и делает этот мир более технологичным. Пусть ваши проекты всегда компилируются без ошибок, а баги исчезают так же быстро, как и появляются! 🚀
Желаем вам вдохновения, новых вызовов и ещё больше успешных решений! Продолжайте менять мир!
P.S. на фото тортик от жены в честь праздника
Please open Telegram to view this post
VIEW IN TELEGRAM
Для чего используется ключевое слово where в Kotlin❓
#quiz
#quiz
Anonymous Quiz
24%
Для работы с Room
18%
Для фильтрации элементов коллекции
55%
Для задания ограничений на типовые параметры в generic-функциях
3%
Для создания анонимных функций
Kotin: in и out, ковариантность и контрвариантность
#kotlin #новичкам
Про in и out написано много, но новички всё равно часто путаются. К тому же, опрос выше показал, что многие разработчики не до конца понимают эту тему. Между тем, знание этой темы даёт ряд преимуществ, и на собеседованиях её часто спрашивают.
Вот одна из хороших статей на эту тему. В статье на примерах рассматривается использование in и out в generic-типах, рассказывается о том, как это было в Java, и приводятся основные юзкейсы, связанные с генериками.
Если вы новичок, то рекомендую прочитать, а профи — наверняка вы и так всё это знаете.🫡
#kotlin #новичкам
Про in и out написано много, но новички всё равно часто путаются. К тому же, опрос выше показал, что многие разработчики не до конца понимают эту тему. Между тем, знание этой темы даёт ряд преимуществ, и на собеседованиях её часто спрашивают.
Вот одна из хороших статей на эту тему. В статье на примерах рассматривается использование in и out в generic-типах, рассказывается о том, как это было в Java, и приводятся основные юзкейсы, связанные с генериками.
Если вы новичок, то рекомендую прочитать, а профи — наверняка вы и так всё это знаете.
Please open Telegram to view this post
VIEW IN TELEGRAM