https://github.com/rabotaru/synthetic-migrate-plugin
Плагин для Android Studio/Intelij IDEA с помощью которого можно мигрировать кодовую базу с котлиновской синтетики на view-binding
https://github.com/rabotaru/synthetic-migrate-plugin
android-studio-plugin idea-plugin kotlin-syntetics psi view-binding
Last synced: about 1 month ago
JSON representation
Плагин для Android Studio/Intelij IDEA с помощью которого можно мигрировать кодовую базу с котлиновской синтетики на view-binding
- Host: GitHub
- URL: https://github.com/rabotaru/synthetic-migrate-plugin
- Owner: RabotaRu
- License: gpl-2.0
- Created: 2022-04-15T08:54:33.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2022-05-16T12:40:30.000Z (over 3 years ago)
- Last Synced: 2025-04-13T21:06:02.697Z (6 months ago)
- Topics: android-studio-plugin, idea-plugin, kotlin-syntetics, psi, view-binding
- Language: Kotlin
- Homepage:
- Size: 94.7 KB
- Stars: 10
- Watchers: 5
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Synthetic Migrate Plugin
## Описание
Плагин для Android Studio/Intelij IDEA с помощью которого можно мигрировать кодовую базу с котлиновской синтетики на view-binding.
Поддерживает Android Studio 4.1+ и Intelij IDEA 2020.1+## Установка
1. Скачать jar [из последнего релиза](https://github.com/RabotaRu/synthetic-migrate-plugin/releases/)
2. Preferences -> Plugins -> Settings -> Install Plugin From Disk![]()
3. Выбрать jar
4. Перезагрузить студию
5. Точка входа в плагин появится в верхнем меню# Описание интерфейса
## Первый таб - Миграция
### Описание
В первом табе происходит настройка миграции, указание сущности которая будет мигрировать, то как будет инициализироваться view binding, где будет инициализироваться, указание доп импортов и т.д.**Чекбокс "Локальная переменная"** - если он установлен, то binding переменная будет создана в методе указанном в поле "Метод инициализации", так что после того как чекбокс становиться активным поле "Метод инициализиации" становиться обязательным
**Поле "Родительский класс"** - это обязательное поле, которое заполняется именем родительского класса сущности которую нужно перевести на view binding. Например нам нужно перевести все сущности которые наследуются от Fragment, значит пишем там Fragment.
**Поле "Название базового класса"** - поле в которе вводится название базового класса сущности. Например нужно перевести все фрагменты на view binding, и есть базовый абстрактный класс BaseFragment, в котором переменная binding установленная абстрактной, следовательно нужно в каждом наследнике BaseFragment переопределять эту переменную. Значит указываем в Поле "Родительский класс" Fragment, в этом поле BaseFragment. И плагин везде где родитель BaseFragment - переопределит binding переменную(добавит override), а где только Fragment - создаст новую.
**Поле "Название binding переменной"** - то как будет называться генерируемая переменная. По умолчания binding
**Поле "Метод инициализации"** - поле которое нужно заполнить если необходимо инициализировать view binding переменную в каком то методе. Она используется как в связке с Чекбоксом "Локальная переменная", так и без него.
1. Если выбран чекбокс и заполнено это поле, то переменная будет создана исключительно в в том методе, который указан в поле
2. Чекбокс не выбран и заполнено поле, будет создана глобальная переменная с lateinit и инициализирована в методе который указан в этом поле**Поле "Шаблон инициализации"** - поле в котором прописывается то как будет инициализирована переменная. Т.к. инициализация сопрежена с обращения к, сгенерированным view binding плагином, классами, то в этом поле можно указать , где это сгенерированный view binding класс, для обрабатываемого класса. Например есть делегат, с помощью которого нужно инициализировать во всех фрагментах binding. Для Фрагмента с лэйаутом R.layout.fragment_search эта инициализация должно выглядеть так val binding by fragmentBindingDelegate(FragmentSearchViewBinding::bind). Значит нужно вписать в это поле by fragmentBindingDelegate(::bind). И тогда в каждом фрагменте, где плагин сможет найти лэйаут будет подставлен класс сгенеренный на основе этого лэйаута.
**Поле "Необходимы импорты"** - плагин по умолчанию удаляет все импорты с синтетикой и добавляет импорты с view binding. На иногда необходимы еще некоторые импорты, например когда используешь тот же делегат для инициализации. Например: ru.rabota.app2.delegate.viewbinding и тогда в списке импортов у каждого обработанного файла появится import ru.rabota.app2.delegate.viewbinding. Это поле так же имеет правило: один импорт - одна строка
**Кнопка "Мигрировать"** - запускает процесс генерации переменной и замены импортов. После нажатия все повиснет и это нормально. После выполнения миграции появится диалог о завершении
**Кнопка "Сбросить"** - сбрасывает все настройки и очищает поля в этом табе
**Кнопка "Отмена"** - закрывает диалог
## Второй таб - Замена родительского класса
![]()
### Описание
Второй таб позволяет заменять родительские классы. Это необходимо если во время переезда на view-binding в родительском классе добавился новый generic и чтобы во всех наследуемых классах руками его не добавлять может пригодится эта фича.**Поле "Что заменяем"** - в этом поле указывается класс от которого наследуются и который изменился/заменился. Например у был класс BaseFragment и стал BaseFragment и везде нужно подставить этот ViewBinding. Значит в этом поле указывается имя такого класса который необходимо заменить т.е. BaseFragment
**Поле "На что заменяем"** - в этом поле указывается выражение на которое заменяется класс указанный выше. Это поле имеет 2 особенности:
1. Когда заменяем BaseFragment на BaseFragment, нужно добавить view binding класс и сохранить имеющуюся уже там viewmodel класс. И тут нам на помощь приходит & , где type аналогичен type из шаблона инициализации, а , где index это индекс generic'а, начиная с 0.
В этом примере в поле будет записано BaseFragment<, <0>>. Где <0> - это ViewModel
2. Так же много где есть аргументы в первичном конструкторе, для того что бы они не исчезли при замене указывается [index] - где index это индекс аргумента, начиная с 0. Например есть BaseItem(abs, test), заменить на SuperItemBase(abs, test). Значит в этом поле нужно указать SuperItemBase<>([0],[1])**Поле "Необходимый импорт"** - импорт который добавляется в процессе замены в каждый обработанный файл. Например: ru.rabota.app2.delegate.viewbinding и тогда в списке импортов у каждого обработанного файла появится import ru.rabota.app2.delegate.viewbinding
**Кнопка "Заменить"** - запускает процесс замены
**Кнопка "Очистить"** - очищает поля
# Примеры использования
## Миграция фрагментов
![]()
Здесь во всех фрагментах сгенерится переменная с именем binding, а в тех кто наследовался от BaseFragment переменная биндинг будет override. Инициализация будет такая binding by someDelegate(NameViewBinding::bind). И в каждый обработанный файл добавиться импорт ru.rabota.app2.delegate.someDelegate. И у всех вьюшек в каждом классе вначале появится binding.
## Миграция итемов списка
![]()
На данном скриншоте приведен пример миграции итема списка. Т.е. во всех классах с родителем Item, в методе onBind будет сгенерирована переменная с названием itemBinding и инициализирована так: itemBinding = NameViewBinding.bind(viewHolder.itemView)## Добавления во всех наследованиях нового дженерика
![]()
В этом примере во все наследования от BaseFragment будет добавлен generic c типом биндинга который был найден в классе. Например:
было MainFragment: BaseFragment()
станет MainFragment: BaseFragment()
И так же во всех классах которые наследуются от BaseFragment, первый дженерик сохранится за счет того что было прописано <0>, и добавится новый с типом биндинга за счет добавления
## Добавления во всех наследованиях нового аргумента
![]()
В этом примере происходит замена наследования с добавлением нового аргумента и сохранением старого. Например:
было MainItem(orientation: Int, data: Int): BaseItem(orientation)
станет MainItem(orientation: Int, data: Int): BaseItem(orientation, data)
И так же во всех классах которые наследуются от BaseItem, первый аргумент сохранится за счет того что было прописано [0], и добавится новый за счет добавления data