Всем привет!
Меня зовут Михаил. Я Android-разработчик в продуктовой команде Циан.
При разработке новой фичи приходится тратить время на создание однотипных файлов, в которых мы будем писать логику. Такие файлы очень похожи друг на друга, зачастую различие только в названии. Будь то создание presentation-слоя c Fragment -> ViewModel -> ComposeWidget (с типовыми State) или data-слоя c интерфейсами, Repository и их реализацией или создание компонента для DI.
Когда сталкиваешься с рутиной, есть желание от неё избавиться. Очень хочется, чтобы всё рутинное создавалось за пару кликов, и ты после этого мог создавать новую функциональность.
В моём представлении в этом могут помочь шаблоны. Вбиваю нужные параметры, и магическим образом всё готово, и всё на своих местах.
Размышляя, в каком виде я хочу видеть этот процесс, я пришёл к таким критериям:
Максимальная комфортность и простота генерации файлов, чтобы, буквально за пару кликов.
Шаблон должен легко модифицироваться всей командой разработки.
Шаблоны не надо искать или скачивать. При свежем develop – свежие шаблоны.
Это точно не скрипт, так как сложно поддерживать его актуальность.
Все должно работать в IDE и легко устанавливаться.
В далёком 2020-м году, Google удалили из AS поддержку кастомных Freemarker-ных шаблонов, альтернатив которым особо не было. А то, что имелось, не подходило моим критериям.
Совместив все критерии, я пришел к выводу, что мне нужен мой собственный plugin для IDE, который полностью удовлетворит все мои потребности.
И я его, знаете-ли, сделал..
Group File Template (GFT) — это плагин для создания классов из подготовленных заранее шаблонов. Настолько гибко, что подойдёт не только Android-разработчику.
Где его найти? В Marketplace IDEA или Android Studio. Просто вбиваем в поиск «GFT». Он там такой один.
![](https://habrastorage.org/getpro/habr/upload_files/7f0/fa7/ffc/7f0fa7ffce4452780f848f16167ae40d.png)
Как работает плагин?
Шаблоны для использования должны находиться в корне вашего проекта в каталоге templates.
![](https://habrastorage.org/getpro/habr/upload_files/6d8/083/d16/6d8083d16e7f11abf48e47e6d7f8c8c3.png)
Файлы с расширением .tm — это абстрактный шаблон класса. На их основе и будут генерироваться классы. За генерацию по этим шаблонам отвечает «main.json».
В шаблон можно добавлять свои параметры, которые будут заполняться из IDE.
Main поддерживает 2 типа параметров:
поле для заполнения, в которое можно ввести любой текст;
выпадающий список, в котором надо будет выбрать один из вариантов.
Плагин создаёт файлы в той папке, из которой было вызвано создание.
Поближе рассмотрим main.json. Он имеет следующую структуру:
{
"name": "TestTemplate", // Название Шаблона
"description": "Example for documentation", // Описание шаблона
"path": "/templates/TestTemplate", // Путь к файлу main шаблона (Заполняется автоматически при создании шаблона из IDE)
"param": [ // Список параметров, которые надо будет ввести при создании файлов из шаблона
"name"
],
"selectParam": [ // Список параметров, которые надо будет выбрать при создании файлов из шаблона
{
"paramName": "ide", // Имя параметра
"paramValue": [ // Список вариантов выбора
"Android Studio",
"Pycharm",
"intellij"
]
},
],
"addFile": [ // Список файлов абстрактных шаблонов класса
{
"name": "{name}[-C]ViewModel.kt", // Имя, с каким создастся файл
"path": "{ide}/viewModels/{name}[-c]", // Путь, по которому будет создан файл
"fileTemplatePath": "example.tm" // Путь до абстрактного шаблона класса в каталоге с шаблоном
}
]
}
Опции
Можно заметить, что рядом с параметрами присутствуют какие-то загадочные символы в квадратных скобках. Например, «[-C]». Всё дело в том, что параметры имеют опции, которые могут поменять значение, вставленное из параметра:
[-s] - snake_case
[-C] - CamelCase
[-c] - camelCase
[-p] - point.between.words
[-sl] - slash/between/word
[-d] - dash-between-word
Например, написав «{"NewFeature"}[-s]», мы получим «new_feature».
Стандартные параметры
Помимо параметров, которые мы указываем в «main.json» файле, существуют стандартные параметры, которые можно применять в шаблоне.
{package} — пакет места, в которое вы делаете создание файла (если создать от каталога внутри модуля /ui/screen, то package будет выглядеть как ru.package.module.ui.screen).
{time} = Текущее время в 12-ти часовом формате -
15:56«03:56».{day} = Текущий день «04».
{month} = Текущий месяц «06».
{year} = Текущий год «2023».
Имена файлов и каталогов
Теперь давайте рассмотрим несколько особенностей и фишек плагина при работе с именами файлов и каталогов.
Если имя файла пустое, плагин создаст только цепочку каталогов, не создавая файл.
{
"name": "",
"path": "path/{name}[-sl]/catalog",
"fileTemplatePath": ""
}
Для добавления файлов в Android-ресурсы пропишите «res/» в параметре «path». Плагин сам найдёт папку res в вашем модуле
{
"name": "{name}[-s]_main.xml",
"path": "res/layout",
"fileTemplatePath": "layout.tm"
}
Чтобы добавить Unit-тест напишите «test/» в параметр «path». Плагин сам найдёт папку test в вашем модуле.
{
"name": "{name}[-C]ViewModelTest.kt",
"path": "test/viewModels/{name}[-c]",
"fileTemplatePath": "example.tm"
}
Бывают случаи, что нам надо создать файлы не только там, где мы вызвали, но и в корне проекта.
Чтобы создать файл в корне проекта, напишите «~/» в «path».
{
"name": "{name}[-C].txt",
"path": "~",
"fileTemplatePath": "example.tm"
}
Актуальные примеры шаблона можно посмотреть тут.
Что писать в .tm файле?
В tm файле находится ваш шаблон. Размечаем его параметрами, которые создали в main.json -> (param или selectParam)
К параметрам применяем нужные нам опции и собственно всё.
package {package}.analytics
import ru.cian.presentation.analytics.base.sender.AnalyticsSender
import {package}.analytics.builder.{name}[-C]Builder
import javax.inject.Inject
class {name}[-C]Analytics
@Inject constructor(
private val analyticsSender: AnalyticsSender
) {
fun {name}[-c]() {
val builder = {name}[-C]Builder()
analyticsSender.sendEvent(builder)
}
}
Если вы добавили .tm файл в шаблон не через IDE, а руками, то не забудьте прописать его в «main.json» как показано выше.
Как создать шаблон?
Вводим название вашего будущего шаблона в диалоговом окне.
![](https://habrastorage.org/getpro/habr/upload_files/c86/e76/c78/c86e76c78f55703ab751a62b44cd1d94.png)
Чтобы создать новый шаблон, нажмите на пункт меню «Tools» -> «Create New Template».
![](https://habrastorage.org/getpro/habr/upload_files/1e5/4e8/c68/1e54e8c68442d25271e0612feadd4f13.png)
Готово. В вашей папке с проектом в подпапке «templates» появился новый шаблон.
![](https://habrastorage.org/getpro/habr/upload_files/842/9e7/74a/8429e774ad490f665d16c339568c8472.png)
Как добавить файл в свой шаблон?
Чтобы добавить файл в шаблон, щёлкните по этому файлу правой кнопкой мыши и выберите «Add File in Template».
![](https://habrastorage.org/getpro/habr/upload_files/081/5f3/0d2/0815f30d24fe30d7ef19256a00597aa5.png)
Плагин попросит вас выбрать, в какой шаблон вы хотите добавить файл (если у вас их несколько).
![](https://habrastorage.org/getpro/habr/upload_files/ad9/2f7/107/ad92f7107f0ec2a60a188cbc22209e0d.png)
Переименовываем файл так, как он будет назван в шаблоне.
![](https://habrastorage.org/getpro/habr/upload_files/b15/db7/0a6/b15db70a6cfb68730fdb29d7464d4f79.png)
Готово, файл появился в выбранном шаблоне и виден в main.json.
"addFile": [
{
"name": "build.gradle.kts",
"path": "",
"fileTemplatePath": "buildTemp.tm"
},
]
Как использовать созданный шаблон?
Кликаем правой кнопкой мыши по папке, в которой хотим создать файлы, и выбираем из списка нужный нам шаблон..
![](https://habrastorage.org/getpro/habr/upload_files/4cb/0ae/abf/4cb0aeabfe9450c4050623f2842e203a.png)
Заполняем параметры в диалоговом окне и нажимаем «OK».
![](https://habrastorage.org/getpro/habr/upload_files/a9c/9f4/8e3/a9c9f48e31d1cec8ec9df14a2324e6a8.png)
Готово, создалась целая структура из шаблона!
Итого!
Что плагин умеет делать, мы разобрались, но чего он пока не умеет делать?
Пока что, не умеет вставлять куски кода в уже существующие файлы (фича на будущее), и чтобы подключить новые модули к app я создаю helpFile.md файл, в котором я прописываю путь до файла, и что в него надо вставить.
В main.json
{
"name": "helpFile.md",
"path": "~",
"fileTemplatePath": "helpFile.tm"
}
и сам шаблон файла
[Добавить в](app/build.gradle.kts)
implementation(project(":kmm_{name}[-s]_api"))
runtimeOnly(project(":kmm_{name}[-s]_impl"))
runtimeOnly(project(":{name}[-s]_compose"))
[Добавить в](settings.gradle.kts)
includeKmmFeatureModule("{name}[-s]")
Плагин помогает мне создавать большие модули, например, для использования kmm нам надо создать 3 модуля, в которых 8 каталогов.
-
api
androidMain
commonMain
-
impl
androidMain
androidTest
commonMain
commonTest
iosMain
-
ui module
androidMain
Он значительно сокращает время от старта фичи в работу до начала написания бизнес логики.
Использую даже для мелких задач, например, нам нужно создать из endPoint дерево каталогов.
Из - /getData/point/v2/map-search
Преобразует в дерево каталогов
![](https://habrastorage.org/getpro/habr/upload_files/5a9/3c6/402/5a93c6402d15754f52fc74f022f51135.png)
Если у вас остались вопросы, пишите мне, всем с радостью отвечу!
Надеюсь, мой плагин облегчит вашу рутинную разработку!
Ccылка на Github
Ссылка на Marketplace
OldFisher
Аки Танос - это безвозвратно разнести в пыль половину проекта.
Louco11 Автор
Нуууу, тут аналогия что также быстро это сделать =))