Site icon AppTractor

Путь Android-приложения к поддержке темной темы: пример Tokopedia

Android 10 уже давно предлагает темную тему для  устройств, и со временем число ее пользователей растет. Темный режим имеет много преимуществ, таких как снижение расхода заряда батареи, улучшение видимости, снижение нагрузки на глаза и т.д.

В этой статье будет рассказано и объяснено, как команда Tokopedia реализовала в своем Android-приложении поддержку темного режима.

Вступление

Мы знаем, что у пользователей есть огромный спрос на функцию темного режима. Что же, ожидание окончено. Tokopedia официально объявила о поддержке темного режима на этапе бета-тестирования. Мы потратили много времени и усилий на преобразование нашего приложения Tokopedia, состоящего из сотен модулей, для обеспечения поддержки темного режима. Было много проблем, с которыми мы столкнулись в этом внедрении. Я поделюсь ими всеми в этой статье, а также нашими решениями.

Что нужно для начала

Базовое понимание темного режима

Лучше всего иметь базовые знания о том, как создать приложение, поддерживающее темный режим. Поэтому в этой статье мы расскажем только об основных препятствиях на пути преобразования нашего приложения. Официальную документацию по темным темам можно найти по этой ссылке.

Вспомогательная библиотека цветов

У нас также есть внутренняя библиотека для хранения и управления цветами. Эта библиотека представляет собой модуль, который содержит colors.xml с values-night ресурсами. Мы рекомендуем использовать этот подход. Таким образом, цвета в вашем приложении централизованы в одном месте, и требуется меньше усилий для их обслуживания.

Принудительно перевести приложение в светлый режим

Пока мы были на этапе разработки, мы применили код, который заставлял приложение работать только в светлом режиме. Принудительный переход в светлый режим не позволит приложению использовать темный режим в продакшене, пока разработчики все еще находятся на этапе разработки.

Представьте, если у нас есть десять страниц, и только две из них уже поддерживают темный режим, а устройство пользователя находится как раз в ночной теме. Тогда у пользователя будет нарушена работа с режимами, перемешанными в приложении. Если мы не переведем приложение в светлый режим, оно автоматически будет следовать системной теме устройства.

Используйте приведенный ниже код, чтобы перевести ваше приложение в светлый режим (поместите его в свой класс application).

AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_NO);

После того, как все экраны смогут поддерживать темную тему, мы сможем начать использовать системную тему по умолчанию и удалить код, который мы создали для принудительного перехода в светлую тему.

Как с минимальными усилиями преобразовать сотни модулей в темный режим?

Поскольку у нас есть сотни модулей, принадлежащих нескольким командам, ручной подход невозможен и требует слишком много усилий. Ручной подход означает, что мы должны менять цвета один за другим, создавать папки ночных ресурсов для цветов, проверять и менять тему. Преобразование может занять целую вечность, и вероятность совершить ошибку высока.

Наше решение — создать скрипт для перевода каждого конкретного модуля в темный режим.

Скрипт автоматизации

Скрипт создан на Python. По сути, он переходит к выбранному модулю и сканирует все файлы, которые обычно содержат цвета, такие как .kt, .java, .xml. Скрипт будет игнорировать файлы с типами, отличными от упомянутых выше.

Если скрипт найдет файл, например, ProductFragment.kt, он откроет его и прочитает строки одну за другой для поиска любого упоминания цвета.

for line in fileinput.input({path_to_product_fragment}, inplace=1):
    # find if line contains color with regex

Регулярное выражение используется для получения конкретного цвета на конкретном шаге, потому что каждый шаг имеет разные ссылки на цвета, которые необходимо заменить. Например, есть такое регулярное выражение:

'com\.[\w_]+\.[\w_]+\.R\.color\.[\w_]+|R\.color\.\w+|\.color\.\w+|@color/\w+|android.R.color.\w+|@android:color/\w+

После того, как в строке найден цвет, скрипт проверит, доступен ли он в нашей библиотеке темного режима. Если он доступен, то цвет необходимо преобразовать в правильный. Скрипт получит соответствующий цвет и заменит его. Пример библиотеки:

Old Color, Dark Mode ColorR.color.Blue_B100,R.color.Unify_B100
@color/Blue_B100,@color/Unify_B100
R.color.Blue_B200,R.color.Unify_B200
@color/Blue_B200,@color/Unify_B200
R.color.Blue_B300,R.color.Unify_B300
@color/Blue_B300,@color/Unify_B300
R.color.Blue_B400,R.color.Unify_B400

Например, в этой строке файла xml мы получаем цвет как @color/Blue_B100, и скрипт изменяет его на основе библиотеки цветов.

android:textColor="@color/Blue_B100" <- before converted
android:textColor="@color/Unify_B100" <- after converted

Как это работает

На самом высоком уровне все можно представить в виде блок-схемы:

В Tokopedia мы сделали три шага, чтобы полностью преобразовать все цвета в поддержку темного режима:

1. Преобразование всех существующих цветов, которые не поддерживаются в темном режиме, в библиотечные.

Как мы упоминали ранее, у нас есть внутренняя библиотека, которая централизовала цвета. К сожалению, предыдущие цвета, которые мы использовали, не всегда поддерживаются в темном режиме, потому что у них нет night значения. Для преобразования мы запускаем скрипт, как мы описали выше.

2. Преобразование всех кастомных цветов в наши внутренние цвета.

В Tokopedia у нас есть сотни модулей, каждый модуль имеет свои собственные цвета (обычно расположенные в res -> values ​​-> colors.xml). Это еще одна проблема, если мы хотим преобразовать их для поддержки темного режима. Таким образом, скрипт будет работать так:

3. Преобразование все жестко прописанных цветов в наши внутренние цвета.

В этом случае мы будем менять жестко закодированный шестнадцатеричные цвета в нашем классе, например, android:background=»#123456″. Подход очень похож на первый:

  1. Пройти по всем классам Android
  2. Найти шестнадцатеричный цвет, используя это регулярное выражение: r’#([0–9a-fA-F]{3}|[0–9a-fA-F]{6}|[0–9a-fA-F]{8})\b’
  3. Получить шестнадцатеричный цвет и перейти в сценарий выбора ближайшего цвета. Скрипт вернет правильный цвет из нашей библиотеки. Например, #123213 превратится в @color/Unify_Black.
  4. Изменить цвет в классе на правильный.

Другие инструменты

Лучшие практики

Результат

Вот некоторые результаты поддержки темного режима в нашем клиентском приложении Tokopedia.

Примерно так мы перевели наше приложение в темный режим. Автоматизация очень помогает нам и снижает количество человеческих ошибок. Но нам все еще нужно постоянно улучшать работу с темным режимом, потому что некоторые варианты необходимо преобразовывать вручную, и они не учитываются в сценарии.

Источник

Exit mobile version