Android & Coffee с Васей
🧹 Небольшая история из-под капота compose-bom.com Поймал любопытный кейс. Google выпустил Compose BOM 2026.05.01, но потом тихо убрал его из официального BOM-маппинга. Причина — рассогласование версий: runtime в этом BOM — 1.10.6, тогда как всё остальное…
Google удалил Compose BOM 2026.06.00 и переопубликовал 2026.05.01, с поправленной runtime зависимостью. Теперь всё чинно.
Если мигрируете — изменения можно посмотреть на https://compose-bom.com/ (или натравите агента — сайт llm-friendly)
Если мигрируете — изменения можно посмотреть на https://compose-bom.com/ (или натравите агента — сайт llm-friendly)
Blueprint Compose Preview
Библиотека от Gus Ward, позволяющая показать Blueprint экрана на Compose.
Достаточно обернуть экран в composable
Есть режим
И удобно, когда дизайнер говорит "вроде тут не 32 пикселя, а 33"
⭐️ Github: https://github.com/GusWard/Blueprint-Compose-Preview
#android #androiddev #jetpackcompose #compose #mobiledev #kotlin #ui #uidesign #androidlibrary
Библиотека от Gus Ward, позволяющая показать Blueprint экрана на Compose.
Достаточно обернуть экран в composable
BlueprintPreview и добавить идентификаторы к некоторым элементам. Удобно для проверки вёрстки и поиска проблем с отступами без запуска приложения.Есть режим
showInternalItems, когда показываются все возможные элементы. Для превью экрана это чересчур (3й скрин), но может пригодиться для превью отдельных компонентов дизайн системыИ удобно, когда дизайнер говорит "вроде тут не 32 пикселя, а 33"
#android #androiddev #jetpackcompose #compose #mobiledev #kotlin #ui #uidesign #androidlibrary
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Один логин?
Приложение собрано. Открываем первую же фичу — логин. Первый экран: ввод номера телефона.
В Jazari Money страна одна — UK. Флаг захардкожен, поменять нельзя. В Jazari One пользователь может сменить код страны прямо в интерфейсе, аудитория глобальная.
Уже здесь — дилемма. Экран ввода телефона в двух приложениях отличается, но не полностью. Различия постарались убрать по максимуму, но от них никуда не деться. Варианта два:
— два отдельных экрана, каждый со своим поведением
— один экран с if'ами
Первый вариант чище концептуально: никаких if-ов, каждое приложение получает свой экран. Но слишком большая часть — вёрстка, валидация телефона, отправка OTP — была бы продублирована.
Вот тут дублировать уже не хочется, потому что расходы на поддержку кажутся большей проблемой, чем при поддержке DI модулей.
Итак, решение — один модуль, одна вьюмодель, одна вьюха, но есть отличия в вёрстке и логике. Как это выразить?
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
Приложение собрано. Открываем первую же фичу — логин. Первый экран: ввод номера телефона.
В Jazari Money страна одна — UK. Флаг захардкожен, поменять нельзя. В Jazari One пользователь может сменить код страны прямо в интерфейсе, аудитория глобальная.
Уже здесь — дилемма. Экран ввода телефона в двух приложениях отличается, но не полностью. Различия постарались убрать по максимуму, но от них никуда не деться. Варианта два:
— два отдельных экрана, каждый со своим поведением
— один экран с if'ами
Первый вариант чище концептуально: никаких if-ов, каждое приложение получает свой экран. Но слишком большая часть — вёрстка, валидация телефона, отправка OTP — была бы продублирована.
Вот тут дублировать уже не хочется, потому что расходы на поддержку кажутся большей проблемой, чем при поддержке DI модулей.
Итак, решение — один модуль, одна вьюмодель, одна вьюха, но есть отличия в вёрстке и логике. Как это выразить?
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
👍4🔥1
Один логин, разное поведение
В Jazari Money при логине нельзя поменять код страны, в Jazari One — можно. Как это сделать?
Вот несколько способов, как сделать фичи настраиваемыми под разные бренды
1️⃣ — общий интерфейс
Но когда отличия накапливаются, на каждое заводить по флагу или другому полю — представьте сколько их будет.
При этом в
Получается примерно так:
Минус: фича знает про то, что бренды есть.
Плюс: фича требует минимум настройки и уже может работать с другим брендом.
2️⃣ Поле
3️⃣ Еще один вариант — конфигурация конкретной фичи вместо общей конфигурации приложения:
Каждая фича — свой конфиг.
Самая чистая абстракция. Но и кода вокруг неё больше.
Пока у нас не white-label и мы не поставляем SDK, большого смысла в таком решении для фич я не вижу. Но это хорошо работает для инфраструктурных модулей с понятной настройкой — например, параметров пушей или Network слоя.
---
В проекте в итоге используются все три подхода — в разных местах и по разным причинам.
Кажется, это и есть ответ: универсального решения нет.
С поведением разобрались. Что с UI?
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
В Jazari Money при логине нельзя поменять код страны, в Jazari One — можно. Как это сделать?
Вот несколько способов, как сделать фичи настраиваемыми под разные бренды
1️⃣ — общий интерфейс
AppVariant. Каждое приложение биндит свою реализацию через DI, а feature-модуль просто спрашивает у него что нужно.
interface AppVariant {
val brand: Brand
val supportEmail: String
// ...
}
brand — универсальное поле, которое позволяет писать if'ы. Более правильным решением было бы завести отдельные поля:
interface AppVariant {
val canChangeCountry: Boolean
val defaultCountry: Country?
val supportEmail: String
// ...
}
Но когда отличия накапливаются, на каждое заводить по флагу или другому полю — представьте сколько их будет.
При этом в
Jazari Money никогда не предвидится выбора другой страны, а дефолтная страна всегда будет UK. То есть абстрагировать здесь сомнительно, хоть и можно. Проверка бренда, пусть и не такая чистая, зато проще.Получается примерно так:
phoneState = when (appVariant.brand) {
// всегда UK
Brand.Money -> PhoneCountry(flag = flag_uk, code = "+44", iso = "GB", canChangeCountry = false)
// выбранная страна состояния
Brand.Global -> loginStorage.savedCountry()
}
Минус: фича знает про то, что бренды есть.
Плюс: фича требует минимум настройки и уже может работать с другим брендом.
2️⃣ Поле
supportEmail в AppVariant — другое дело. Оно используется в нескольких местах, присутствует в обоих приложениях и имеет разные значения. Здесь уже есть смысл сделать поле вместо if'ов по всем модулям.3️⃣ Еще один вариант — конфигурация конкретной фичи вместо общей конфигурации приложения:
data class EnterPhoneConfig(
val canChangeCountry: Boolean,
val defaultCountry: Country?,
)
Каждая фича — свой конфиг.
AppVariant не разрастается хаотично.Самая чистая абстракция. Но и кода вокруг неё больше.
Пока у нас не white-label и мы не поставляем SDK, большого смысла в таком решении для фич я не вижу. Но это хорошо работает для инфраструктурных модулей с понятной настройкой — например, параметров пушей или Network слоя.
---
В проекте в итоге используются все три подхода — в разных местах и по разным причинам.
Кажется, это и есть ответ: универсального решения нет.
С поведением разобрались. Что с UI?
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
🔥3
This media is not supported in your browser
VIEW IN TELEGRAM
🤯 Новый One UI от Samsung
За такое нужно увольнять без выходного пособия. И дизайнера, и разработчика.
У меня уже дёргается глаз от этой анимации.
Что думаете?
#android #ux #samsung #oneui
За такое нужно увольнять без выходного пособия. И дизайнера, и разработчика.
У меня уже дёргается глаз от этой анимации.
Что думаете?
#android #ux #samsung #oneui
💯2
This media is not supported in your browser
VIEW IN TELEGRAM
Прикольная пасхалка от Google Play консоли
Один логин, разный UI
В Jazari Money дизайн-системы как артефакта почти не существовало — она была в чертогах разума, но несколько компонентов всё же просочились в Figma.
Android жил на Material-токенах, iOS придумал свои. Тёмная тема была только в iOS приложении силами и энтузиазмом iOS команды. Не потому что не знали как нужно: качественная дизайн система — отдельная большая работа. Легко сделать плохо и заиметь еще бОльший долг.
Дизайнер приносит дизайн Jazari One. Конечно, с мыслью о переиспользовании — но сразу появились отличия: только тёмная тема, другие цвета с другой семантикой, новые токены типографики, кнопки нарисованы заново.
Три варианта: копировать экраны, добавлять if-ы или привести к одному виду.
Копировать — больно: отличия в деталях, а поддерживать придётся почти каждый экран. Поэтому стандартизировали токены, привели кнопки к единому виду и волевым решением перевели Jazari Money на новые токены. В большой компании такое не позволишь — в стартапе это задача на пару дней.
За счёт этого получилось достаточно абстрагировать дизайн-систему. Оставшиеся детали — лобзиком через if'ы с помощью
Так условный
Сейчас
🤖 Переезд на новые токены целиком выполнил AI — на вход получил только ссылку на Figma и указания: как мапить и что тема теперь будет своя, а не Material. Тюнинг компонентов if'ами был ручным, потому что мы сами продолжали их активно менять.
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
В Jazari Money дизайн-системы как артефакта почти не существовало — она была в чертогах разума, но несколько компонентов всё же просочились в Figma.
Android жил на Material-токенах, iOS придумал свои. Тёмная тема была только в iOS приложении силами и энтузиазмом iOS команды. Не потому что не знали как нужно: качественная дизайн система — отдельная большая работа. Легко сделать плохо и заиметь еще бОльший долг.
Дизайнер приносит дизайн Jazari One. Конечно, с мыслью о переиспользовании — но сразу появились отличия: только тёмная тема, другие цвета с другой семантикой, новые токены типографики, кнопки нарисованы заново.
Три варианта: копировать экраны, добавлять if-ы или привести к одному виду.
Копировать — больно: отличия в деталях, а поддерживать придётся почти каждый экран. Поэтому стандартизировали токены, привели кнопки к единому виду и волевым решением перевели Jazari Money на новые токены. В большой компании такое не позволишь — в стартапе это задача на пару дней.
За счёт этого получилось достаточно абстрагировать дизайн-систему. Оставшиеся детали — лобзиком через if'ы с помощью
Brand в CompositionLocal:
@Composable
fun JazariTheme(
brand: Brand,
...
) {
CompositionLocalProvider(
LocalBrand provides brand,
content = content,
)
}
Так условный
JazariButton может выбирать реализацию по бренду:
@Composable
private fun getContainerColor(type: ButtonType) = when (type) {
ButtonType.Primary -> when (LocalBrand.current) {
Brand.Money -> JazariTheme.colorScheme.accentGreen
Brand.Global -> Color.Transparent
}
// ...
}
Сейчас
LocalBrand.current встречается в коде 54 раза. Много, но все отличия между приложениями сразу видны. Но те же 54 места превратились бы в 54 настраиваемых параметра. Это уже не абстракция — это другой проект.🤖 Переезд на новые токены целиком выполнил AI — на вход получил только ссылку на Figma и указания: как мапить и что тема теперь будет своя, а не Material. Тюнинг компонентов if'ами был ручным, потому что мы сами продолжали их активно менять.
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
👍2
Claude может сам настроить мониторинг токенов
Claude Code и другие coding-ассистенты умеют отдавать телеметрию через OpenTelemetry — токены, latency, события агента.
Подключается к Grafana или любому OTEL совместимому коллектору. Есть бесплатный облачный вариант, можно поднять своё.
Пригождается когда упираешься в лимиты или хочешь понять, куда реально уходят токены.
Ну и просто прикольно видеть, что потратил 500 баксов на токены, а подписка стоит $100
https://code.claude.com/docs/en/agent-sdk/observability
#claude #claudecode #ai #devtools #observability
Claude Code и другие coding-ассистенты умеют отдавать телеметрию через OpenTelemetry — токены, latency, события агента.
Подключается к Grafana или любому OTEL совместимому коллектору. Есть бесплатный облачный вариант, можно поднять своё.
Пригождается когда упираешься в лимиты или хочешь понять, куда реально уходят токены.
Ну и просто прикольно видеть, что потратил 500 баксов на токены, а подписка стоит $100
https://code.claude.com/docs/en/agent-sdk/observability
#claude #claudecode #ai #devtools #observability
❤1
Про то, как AI не смог
Jazari One — приложение со стейблкоинами. Один из важных типов —
Нужно было расширить тип, чтобы он умел работать и с фиатом, и с токенами.
Вопрос был один: как определить, что перед нами — фиат или токен? AI решил проверять длину строки: USD — три символа, USDT — четыре. Звучит правдоподобно ровно до момента, когда вспоминаешь про BTC, SOL, ETH или стейблкоин DAI.
Следующая идея от AI — делегировать Java:
Тут сразу две проблемы:
• исключение — это слишком медленно. Выбросить исключения в разы или десятки раз медленнее возврата результата
• на Android есть нюанс: ICU добавляет некоторые трёхсимвольные криптовалюты — в частности, ETH и BTC — как «настоящие» валюты, просто с
🫴 Финальное решение — явно фильтровать по numericCode (на скрине), который соответствует ISO 4217:
Набор фиатных валют строится один раз, лениво. ETH и BTC учтены. Определение типа валюты — O(1)
Три попытки ушло у AI, чтобы написать одну функцию. Не забывайте проверять за AI
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
Jazari One — приложение со стейблкоинами. Один из важных типов —
Money, работает поверх java.util.Currency. Но старая реализация не подходит: вызов Currency.getInstance("USDT") просто бросил бы исключение.Нужно было расширить тип, чтобы он умел работать и с фиатом, и с токенами.
sealed interface MoneyCurrency {
val currencyCode: String
data class Fiat(val currency: Currency) : MoneyCurrency { ... }
data class Token(val symbol: String) : MoneyCurrency { ... }
}
Вопрос был один: как определить, что перед нами — фиат или токен? AI решил проверять длину строки: USD — три символа, USDT — четыре. Звучит правдоподобно ровно до момента, когда вспоминаешь про BTC, SOL, ETH или стейблкоин DAI.
Следующая идея от AI — делегировать Java:
fun fromCode(code: String): MoneyCurrency {
return try {
Fiat(Currency.getInstance(code))
} catch (e: IllegalArgumentException) {
Token(code)
}
}
Currency.getInstance() знает все ISO 4217 коды. Не знает — значит, токен. Выглядит элегантно.Тут сразу две проблемы:
• исключение — это слишком медленно. Выбросить исключения в разы или десятки раз медленнее возврата результата
• на Android есть нюанс: ICU добавляет некоторые трёхсимвольные криптовалюты — в частности, ETH и BTC — как «настоящие» валюты, просто с
numericCode == -1. Поэтому Currency.getInstance("ETH") не бросает исключение, и ETH молча стал бы фиатом.🫴 Финальное решение — явно фильтровать по numericCode (на скрине), который соответствует ISO 4217:
private val fiatCurrencies: Map<String, Currency> by lazy {
Currency.getAvailableCurrencies()
.filter { it.numericCode > 0 }
.associateBy { it.currencyCode }
}
fun fromCode(code: String): MoneyCurrency {
val currency = fiatCurrencies[code]
return if (currency != null) Fiat(currency) else Token(code)
}
Набор фиатных валют строится один раз, лениво. ETH и BTC учтены. Определение типа валюты — O(1)
Три попытки ушло у AI, чтобы написать одну функцию. Не забывайте проверять за AI
→ серия «Два приложения — один логин»
#android #kotlin #androiddev #архитектура
👍5
Media is too big
VIEW IN TELEGRAM
💳 Экран карт — возможно, один из самых сложных экранов в банковских приложениях с точки зрения UX
Когда говорим о картах, мы чаще всего представляем обычные карточки, которыми расплачиваемся в магазинах. Даже виртуальные карты повторяют эту ассоциацию: их нет в реальном мире, но их рисуют как настоящие карты.
Поэтому отображение карт в приложении часто пытаются сделать осязаемым:
• складывают их в виде кошелька, чтобы их можно было "доставать" жестами
• добавляют 3d модели, чтобы карта выглядела сочно (так сделано, например, в iOS приложении Jazari)
• добавляют всяческие анимации
С другой стороны, вокруг карт есть целая цифровая экосистема:
• транзакции
• управление картой: пин, заморозка, показ деталей, закрытие
• разные бонусные программы
• возможность взаимодействия с кошельками Google Wallet, Apple Pay и другими
• лимиты
• и много чего еще
При сложении этих двух больших частей вместе получается бесконечное количество возможных UX решений. И всё это нужно программировать👨💻
Такие неоднозначные случаи часто спрашивают на собесах. Для примера, на видео:
— есть два разных горизонтальных скролла: свайп между самими картами и скролл внутри контента выбранной карты
— можно проскроллить вертикально, при этом карты должны остаться на экране
— есть показ деталей карты — его решили сделать прямо поверх карты, для этого нужно учитывать все требования выше
✏️ Го обсудим, как бы вы верстали экран как на видео?
Когда говорим о картах, мы чаще всего представляем обычные карточки, которыми расплачиваемся в магазинах. Даже виртуальные карты повторяют эту ассоциацию: их нет в реальном мире, но их рисуют как настоящие карты.
Поэтому отображение карт в приложении часто пытаются сделать осязаемым:
• складывают их в виде кошелька, чтобы их можно было "доставать" жестами
• добавляют 3d модели, чтобы карта выглядела сочно (так сделано, например, в iOS приложении Jazari)
• добавляют всяческие анимации
С другой стороны, вокруг карт есть целая цифровая экосистема:
• транзакции
• управление картой: пин, заморозка, показ деталей, закрытие
• разные бонусные программы
• возможность взаимодействия с кошельками Google Wallet, Apple Pay и другими
• лимиты
• и много чего еще
При сложении этих двух больших частей вместе получается бесконечное количество возможных UX решений. И всё это нужно программировать
Такие неоднозначные случаи часто спрашивают на собесах. Для примера, на видео:
— есть два разных горизонтальных скролла: свайп между самими картами и скролл внутри контента выбранной карты
— можно проскроллить вертикально, при этом карты должны остаться на экране
— есть показ деталей карты — его решили сделать прямо поверх карты, для этого нужно учитывать все требования выше
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1