Перейти к содержимому
Источник

Про миграцию с Material 2 на Material 3

Мы часто говорим, что у нас в проекте есть своя дизайн-система. На самом деле она своя, конечно, отчасти. По сути мы абстрагировали от продуктового разработчика те компоненты и токены, с которыми он работает. То есть, если раньше он просто брал кнопки и тексты из Material 2, то теперь он берёт их из модуля дизайн-системы.

Но реализация-то никуда не делась. Button, Text или условный Scaffold из нашей дизайн-системы – это обёртка аналогов из M2. Только система токенов целиком своя и ряд новых компонентов типа аватарок. Своё всё не делаем потому, что дизайнеры лапочки и берут за образец Material компоненты, они выглядят почти аналогично. Плюс мы не верим, что у нас получится хорошо, если даже у гугла не получилось.

Дизайнеры начали переводить свои компоненты на M3, что сильно заметно по каким-нибудь свитчам и лоадерам. Мы, соответственно, хотим:

  • актуализировать дизайн под новые макеты
  • получить поддержку инсетов из коробки
  • всякие календари, дейт-пикеры и другие новые компоненты
  • и много чего ещё, что в M2 никогда уже не будет

У гугла есть документация по миграции с M2 на M3, но шаги там выглядят примерно как в меме о рисовании совы. Говорят, можно держать в проекте одновременно и M2 и M3, но осторожно и, желательно, недолго. Постепенно таким образом переводите компоненты с M2 на M3, и отказываетесь в итоге от первого окончательно. Базар жок.

Сложность, очевидно, в этом "постепенно". Мы сходу решили просто декомпозировать эту задачу на перевод отдельных компонентов, и поначалу шло неплохо. А потом где-то на полпути мы перевели m2.Text на m3.Text и поняли, что так делать нельзя 😔

Text, как и некоторые другие компоненты, подвязан на какие-то специфичные CompositionLocal из темы. Для того, чтобы это работало с M2-компонентом, мы прокидывали m2.LocalContentColor и m2.LocalTextStyle. Мы продумали это заранее и начали прокидывать из темы ещё и m3.LocalContentColor с m3.LocalTextStyle. И вы думаете всё заработало? Ну да, на первый взгляд, компонент Text, где его использовали мы – починился.

Но есть нюанс. Другие компоненты, например TextField или BottomNavigationItem, до которых у нас руки ещё не добрались. Оказывается, они в своих недрах тоже переопределяют m2.LocalContentColor и m2.LocalTextStyle для того, чтобы летающий плейсхолдер у текстового поля или название таба (читай m2.Text внутри) кастомизировать. Ты начинаешь внутри использовать m3.Text, m2.TextField внутри переопределяет m2.LocalTextStyle. Соответственно, m3.Text внутри никак под это не подстраивается, потому что ожидает m3.LocalTextStyle. 😐

(А ещё там вообще захардкожены токены из M2 и шрифты, например, и так у нас никогда там не работали, но это уже другая история)

Отсюда вывод. Нельзя так просто взять и перевести по одному компоненты со второго материала на третий. Алгоритм следующий:

  • берёте очередной компонент
  • закапываетесь в его кишки по самый foundation
  • если видите переопределение или использование CompositionLocal из темы – перекладываете в конец очереди
  • берётесь за следующий
  • а всё оставшееся потом надеетесь разом переписать. Есть шансы, что получится.

Или есть более логичный, но сложный вариант. По славной традиции кишочки M3 компонентов вытаскиваем наружу. И в этом процессе везде, где есть CompositionLocalProvider – провайдим и M2 и M3 версии локалов. Когда закончим полный переход, вероятно, кишочки можно будет обратно заправить.

PS. Лица наши представили, когда на неделе от гугла потекли слухи о том, что они там новую версию материала готовят? 👌