Mobile вызывает. Ответите? 📱
VK JT Mobile Meetup на связи сразу в двух городах:
📍 В Москве — 31 октября
📍 В Санкт-Петербурге — 14 ноября
В Москве вас ждут два параллельных трека — iOS и Android, а в Петербурге — один общий мобайл-трек.
На проводе будут инженеры ВКонтакте, Дзена, MAX, VK Tech и других команд ВК. В программе — реальные кейсы мобильной разработки: 120 FPS, анализ влияния, сравнительные тесты, ИИ, архитектура и другие задачи производства.
После докладов можно обсудить кейсы с другими разработчиками, поучаствовать в интерактивах и пообщаться на вечеринке.
Мероприятие рассчитано на iOS- и Android-разработчиков и пройдут только офлайн. Принимайте вызов в своём городе!
→ Регистрация
#реклама
VK JT Mobile Meetup на связи сразу в двух городах:
📍 В Москве — 31 октября
📍 В Санкт-Петербурге — 14 ноября
В Москве вас ждут два параллельных трека — iOS и Android, а в Петербурге — один общий мобайл-трек.
На проводе будут инженеры ВКонтакте, Дзена, MAX, VK Tech и других команд ВК. В программе — реальные кейсы мобильной разработки: 120 FPS, анализ влияния, сравнительные тесты, ИИ, архитектура и другие задачи производства.
После докладов можно обсудить кейсы с другими разработчиками, поучаствовать в интерактивах и пообщаться на вечеринке.
Мероприятие рассчитано на iOS- и Android-разработчиков и пройдут только офлайн. Принимайте вызов в своём городе!
→ Регистрация
#реклама
❤4👎2👍1
Compose Broadcast
#Compose #AndroidDev #AI
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20👎1
В 1.13.0-alpha03 (сейчас уже beta01)
BasicTextField(value, onValueChange) и такие же перегрузки Material 2 TextField помечены deprecated. Замена — state-based API на TextFieldState.👉 Маски:
VisualTransformation тоже deprecated, переходите на OutputTransformation. Пишете insert(4, "-"), а offset mapping считается автоматически👉 Фильтрация переезжает из
onValueChange в InputTransformation. maxLength deprecated: вместо него maxLengthTrim (обрезает) и maxLengthReject (отклоняет ввод)👉 ViewModel: держать
TextFieldState во ViewModel нормально, но отдельно от UiState👉 Кому и когда: всем, у кого есть формы. Пока это только предупреждения компилятора, код собирается. Мигрировать лучше заранее, особенно маски и
StateFlow-формы// было
TextField(value = text, onValueChange = { text = it })
// стало
TextField(state = rememberTextFieldState())
🔗 Гайд по миграции
🔗 Release notes
#Compose #JetpackCompose #Android
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24👎9❤7
⚙️ Вышел Compose Multiplatform 1.12.2
Патч к 1.12.1 без новых фич — три точечных фикса. Gradle-плагин и библиотеки:
👉 Multiple platforms: убрали мигание при анимации непрямоугольных
👉 iOS: краш, когда
👉 Web: поведение фокуса backing text input под iOS Safari 27.0 (#3466)
Material3 в этом релизе по‑прежнему на
🔗 Release notes 1.12.2
#Compose #CMP #KMP
Патч к 1.12.1 без новых фич — три точечных фикса. Gradle-плагин и библиотеки:
org.jetbrains.compose:1.12.2.👉 Multiple platforms: убрали мигание при анимации непрямоугольных
graphicsLayer-теней (#3465)👉 iOS: краш, когда
TextField терял фокус из‑за показанного Dialog (#3459)👉 Web: поведение фокуса backing text input под iOS Safari 27.0 (#3466)
Material3 в этом релизе по‑прежнему на
1.12.0-alpha03, Navigation3 — 1.2.0-rc01. Имеет смысл обновиться, если ловили эти баги.🔗 Release notes 1.12.2
#Compose #CMP #KMP
❤7👎1🔥1
Google переписал гайды Modular with Hilt и Modular with Koin: каждый feature-модуль теперь регистрирует не только свои экраны, но и сопоставитель (matcher) для диплинка. Вот как это делает модуль профиля в варианте с Hilt:
@IntoSet
@Provides
fun provideDeepLinkMatcher(): BackStackMatcher<*, NavKey> =
UriDeepLinkMatcher(
uriPattern = DeepLinkUri(PROFILE_URI),
serializer = Profile.serializer(),
).withBackStack { matchResult ->
listOf(ConversationList, matchResult.key)
}
Navigator.handleDeepLink(intent) в модуле common перебирает все такие сопоставители и по URI собирает искусственный стек экранов, а для обычного запуска и запуска по диплинку в примерах заведены отдельные Activity. Так фичу можно открыть по ссылке, не зная, как устроена навигация в соседних модулях.🔗 Hilt · Koin
#Compose #Navigation3 #AndroidDev
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20👎1
🧭 Навигация из Android-приложения переезжает в общий код Compose Multiplatform
В JetBrains напомнили Android-разработчикам: знакомые
Мультиплатформенную поддержку в библиотеку AndroidX Navigation добавляет команда Compose Multiplatform, поэтому подход тот же, что на Android: маршрут — сериализуемый объект или data class с аргументами, а граф описывается внутри
Подключается всё одной зависимостью
🔗 Navigation in Compose · пост Kotlin
#Compose #ComposeMultiplatform #Kotlin #Navigation
В JetBrains напомнили Android-разработчикам: знакомые
NavController и NavHost можно вынести в общий код и получить одну модель навигации с типобезопасными маршрутами, одним графом и одним стеком экранов на Android, iOS, десктопе и в вебе. Всё это собрано в разделе документации Kotlin Multiplatform «Navigation in Compose».Мультиплатформенную поддержку в библиотеку AndroidX Navigation добавляет команда Compose Multiplatform, поэтому подход тот же, что на Android: маршрут — сериализуемый объект или data class с аргументами, а граф описывается внутри
NavHost:@Serializable
object Profile
@Serializable
object FriendsList
val navController = rememberNavController()
NavHost(navController = navController, startDestination = Profile) {
composable<Profile> { ProfileScreen( /* ... */ ) }
composable<FriendsList> { FriendsListScreen( /* ... */ ) }
}
Подключается всё одной зависимостью
org.jetbrains.androidx.navigation:navigation-compose в commonMain. Жест «назад» библиотека переводит в возврат на предыдущий экран на каждой платформе: на iOS это свайп, на десктопе — клавиша Esc. Для iOS по умолчанию включена анимация перехода в духе нативной, но если задать свои enterTransition или exitTransition, она отключится. Выключить обработку жеста на iOS можно флагом enableBackGesture = false в ComposeUIViewController.⚠️ Диплинки по умолчанию не видны внешним приложениям: URI-схему нужно отдельно зарегистрировать в каждой целевой ОС. А если на iOS нужны системные эффекты вроде Liquid Glass в навигационном интерфейсе, документация советует перенести навигацию в нативный SwiftUI и оставить Compose для содержимого экранов.
🔗 Navigation in Compose · пост Kotlin
#Compose #ComposeMultiplatform #Kotlin #Navigation
👍15❤2👎2
This media is not supported in your browser
VIEW IN TELEGRAM
В августе Compose Foundation 1.12 научил
TextFieldState хранить SpanStyle и ParagraphStyle вместе с текстом. Но как сделать кнопку «жирный», которая работает с выделением и не ломается при правках, приходилось разбираться самим. Теперь в документации есть отдельный гайд, а полная реализация лежит в сэмпле Jetchat.Ключевая настройка —
ExpandPolicy: она решает, подхватит ли стиль текст, напечатанный ровно на его границе. AtEnd ведёт себя как обычный редактор, InsideOnly подходит для @упоминаний, которые не должны «расползаться».state.edit {
addStyle(
spanStyle = SpanStyle(fontWeight = FontWeight.Bold),
range = selection,
expandPolicy = ExpandPolicy.AtEnd
)
}addStyle возвращает TrackedRange, который сам сдвигается при правках и живёт только внутри edit. Для тулбара и сериализации есть TextFieldState.textStyles.🔗 Гайд · Jetchat
#Compose #JetpackCompose #Android
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥27👎1
Compose Desktop работает только на JVM, поэтому даже маленькая утилита едет к пользователю вместе с Java. Автор compose-desktop-native пошёл другим путём: собрал Compose на Kotlin/Native, а окна, ввод, звук, диалоги и буфер обмена отдал SDL3. На выходе получается один исполняемый файл для macOS, Linux или Windows, без JVM.
Compose при этом не переписан: runtime берётся официальный, а
ui, foundation и material3 скопированы из Compose Multiplatform как есть. Рисует всё тот же Skia.fun main() = nativeComposeWindow(title = "Hello") {
Text("Hello from Compose Desktop Native")
}В свой проект его подключают Gradle-плагином: вы объявляете обычные зависимости Compose, а плагин подменяет их на порт только для нативных desktop-таргетов. Android, JVM, iOS и Web продолжают собираться на официальных артефактах.
⚠️ Это сторонний проект, а не JetBrains: артефакты — форк com.bitsycore, на Windows используется форк Skiko. Репозиторию четыре месяца.🔗 GitHub · Пример с плагином
#Compose #CMP #KotlinNative #Desktop
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥35👎1
В начале октября в kotlinlang #compose спросили: как на сервере отрендерить Compose UI в PDF, например для генерации счетов? На Android есть PDF API с
Canvas, а на JVM? Через ImageComposeScene получится только картинка внутри PDF, без векторного текста. Skia умеет писать PDF сама, но в Skiko эта поддержка так и не появилась (SKIKO-1017). Автор вопроса в итоге остановился на готовой библиотеке compose2pdf.compose2pdf работает на Compose Desktop: перехватывает отрисовку через SVGCanvas Skia и переводит её в PDF через PDFBox. Текст остаётся выделяемым, шрифты встраиваются, страницы разбиваются автоматически, а результат можно стримить прямо из Ktor.
val pdf = renderToPdf(config = PdfPageConfig.A4WithMargins) {
Text("Invoice #1234", fontSize = 24.sp, fontWeight = FontWeight.Bold)
Text("Amount: $1,250.00")
}Если PDF нужен и в мобильном приложении, есть compose-multiplatform-pdf-export для Android, iOS и JVM: на Android он пишет через
PdfDocument, на iOS — в PDF-контекст CoreGraphics.⚠️ compose2pdf — только JVM, Android и iOS он не поддерживает. Обе библиотеки сторонние и появились в этом году.
🔗 Обсуждение · compose2pdf · compose-multiplatform-pdf-export
#Compose #CMP #KMP #PDF
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥6❤5👎1
Forwarded from AI Dev Broadcast
Агент может написать экран на Compose, который компилируется, но не видит, что отступ съехал, текст обрезан, а кнопка не того цвета. Это выясняется, только когда вы откроете IDE. Spyglass закрывает этот пробел: рендерит
@Preview в PNG без IDE, эмулятора и устройства и сравнивает результат с макетом.В ответ агент получает процент совпадения, список отличающихся областей в px и dp и тепловую карту. Дальше он сам правит код и сравнивает снова. В демо так нашлась даже ошибка в одной букве: «Priority Support» вместо «Priority support».
Работает из командной строки, в CI и как MCP-сервер для Claude и других агентов. Билд-файлы трогать не надо: CLI запускает ваш
gradlew со своим init-скриптом только на время рендера.⚠️ Проект на ранней стадии (0.1.0, появился 15 октября): сейчас рендерятся превью из commonMain и desktop-кода Compose Multiplatform, Android-only превью пока только в планах.🔗 GitHub · Релиз
#AI #MCP #Compose #KMP
Please open Telegram to view this post
VIEW IN TELEGRAM
👍23❤2👎1
🐱 nav3-uikit: Navigation 3 в CMP с настоящим UINavigationController на iOS
Автор nav3-uikit предлагает простую сделку: переименуйте
Каждый экран — отдельный
🔗 GitHub · Как это устроено
#Compose #CMP #Navigation3 #iOS
Автор nav3-uikit предлагает простую сделку: переименуйте
NavDisplay в NativeNavDisplay, и экраны Compose Multiplatform на iOS окажутся внутри настоящего UINavigationController. Кнопка «Назад», свайп от края и меню истории — уже не имитация, а сам UIKit.NativeNavDisplay(
backStack = backStack,
onBack = { backStack.removeLastOrNull() },
entryProvider = entryProvider {
entry<Home>(metadata = NativeNavigation.title("Home", large = true)) { HomeScreen() }
},
)
Каждый экран — отдельный
ComposeUIViewController, а через metadata можно включить large title или открыть экран как нативный sheet. Для вкладок есть NativeTabDisplay с UITabBarController. Источником правды остаётся ваш back stack: системный pop вызывает onBack, а если приложение его отклонит, экран вернётся на место. На Android и десктопе всё работает через обычный NavDisplay.⚠️ Проект экспериментальный: версия 0.1.0-dev01, репозиторий создан 16 октября. Нативные вкладки требуют iOS 18+.
🔗 GitHub · Как это устроено
#Compose #CMP #Navigation3 #iOS
👍14🔥4👎1
Дизайн-система есть почти у каждой команды, но через пару месяцев на одном экране отступ
16.dp, на другом 18.dp, где-то свой TextStyle и захардкоженный hex-цвет. Ревью всё не ловит. Ravi Rawal предлагает считать дизайн-систему инженерным контрактом и проверять его автоматически.Konsist следит за архитектурой: фичи не должны зависеть от внутренностей дизайн-системы.
Konsist.scopeFromProject().assertArchitecture {
val features = Layer("Features", "com.acme.feature..")
val dsInternal = Layer("DS Internal", "com.acme.designsystem.internal..")
features.doesNotDependOn(dsInternal)
}Но
Color(0xFF1769E0) прямо в фиче такой тест пропустит. Здесь нужен свой Lint-детектор, а UI-тесты проверяют то, что видно только в рантайме.⚠️ Детектор из статьи — стартовый: Color.Red или цвет из константы он не поймает.
🔗 Статья · Konsist
#Compose #JetpackCompose #Android #Konsist
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍2👎1
⚙️ Прогрессивный blur в Compose: Google выпустил гайд по новым API из 1.13
До сих пор
Радиус теперь меняется по поверхности: градиентом сверху вниз, слева направо, по линии или от точки. Например, так края списка размываются, а центр остаётся чётким:
🔗 Гайд · Примеры
#Compose #JetpackCompose #Android
До сих пор
Modifier.blur умел одно: размыть композабл целиком с одинаковым радиусом. Чтобы края списка мягко уходили в размытие, приходилось писать свой шейдер или брать библиотеку вроде Haze. В Compose UI 1.13.0-beta01 появились BlurRadiusSpec и BlurStop, и теперь в документации есть гайд и готовые рецепты.Радиус теперь меняется по поверхности: градиентом сверху вниз, слева направо, по линии или от точки. Например, так края списка размываются, а центр остаётся чётким:
LazyColumn(
modifier = Modifier.blur(
blurRadiusSpec = BlurRadiusSpec.verticalGradient(
stops = listOf(
BlurStop(fraction = 0f, radius = 18.dp),
BlurStop(fraction = 0.42f, radius = 0.dp),
BlurStop(fraction = 0.58f, radius = 0.dp),
BlurStop(fraction = 1f, radius = 18.dp),
),
),
edgeTreatment = BlurredEdgeTreatment.Unbounded,
),
) { /* ... */ }
⚠️ Modifier.blur размывает то, что рисует сам композабл. Размытие фона под панелью (backdrop blur) гайд не покрывает, а переменный радиус ограничен 150 px.🔗 Гайд · Примеры
#Compose #JetpackCompose #Android
👍20👎1
Экран дёргается, Layout Inspector показывает растущий счётчик рекомпозиций, но не говорит главного: какой параметр или стейт её вызвал. ComposeStateMonitor отвечает как раз на этот вопрос. Вы вешаете на функцию
@ComposableMonitor, плагин компилятора дописывает в неё отслеживание параметров и State-переменных, и при каждой рекомпозиции в лог падает строка:CounterLabel recomposed because
`count` changed from `0` to `1`
Работает на всех таргетах Compose Multiplatform: Android, desktop, iOS, wasmJs и js. Нужны Kotlin 2.0+ (под каждую линию 2.0–2.4 своя сборка плагина), Gradle 7.6+ и Compose 1.6.11+. На Android по умолчанию инструментируется только
debug, на остальных платформах мониторинг лучше включать Gradle-свойством. Идея и трекер изменений взяты из Rebugger, но здесь не нужно вручную перечислять, что отслеживать.⚠️ Проект совсем свежий: репозиторий появился 22 октября, версия 0.2.0. Лямбды, локальные функции и стейт во вложенных блоках пока не отслеживаются.
🔗 GitHub
#Compose #CMP #KMP #Android
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥29👎1
This media is not supported in your browser
VIEW IN TELEGRAM
CmpDevicePreview от Apadmi рисует приложение на Compose Multiplatform в рамке устройства. Рядом панель, в которой переключаются модель, ориентация, тёмная тема, размер текста, язык и клавиатура. Работает на Android, iOS, macOS, Desktop, JS и Wasm, поэтому веб-демо приложения можно выложить в интернет.
Insets,
🔗 GitHub · Live demo
#Compose #ComposeMultiplatform #KMP #Kotlin
implementation("com.apadmi:cmpdevicepreview:0.1.0")
DeviceWithConfigurationView {
App()
}Insets,
isSystemInDarkTheme(), font scale и window size classes внутри рамки берутся от симулированного устройства, так что менять код приложения не нужно. В вебе настройки попадают в URL, и превью можно отправить ссылкой.⚠️ На Android нельзя подменить insets и тёмную тему хоста, а диалоги выходят за рамку. Версия 0.1.0, API ещё меняется.
🔗 GitHub · Live demo
#Compose #ComposeMultiplatform #KMP #Kotlin
🔥14👍7👎2
На Google I/O команда Compose показала Styles, новый способ настраивать внешний вид компонентов. Теперь она сообщила, что по итогам отзывов API станет менее навязчивым: определения визуальных свойств переедут из слоя foundation в слой дизайн-системы, то есть в Material или вашу собственную. Дизайн-система сама решит, какие свойства её компонентов можно стилизовать, а свои свойства можно будет объявлять через
stylePropertyOf и styleLocalOf.Пока идёт переделка, с developer.android.com сняли весь раздел про Styles (основы, темизацию, анимации состояний, сравнение с Modifier, рекомендации и ограничения), а также опубликованный ранее скилл для AI-агентов. В Compose 1.13 Styles API остаётся
@Experimental.⚠️ Если вы уже пробовали Styles в коде, API ещё поменяется. Новую форму обещают показать отдельно и собрать по ней отзывы.
🔗 Styles update
#Compose #JetpackCompose #Android
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥4
Анимированные стикеры Telegram приходят в формате TGS — это Lottie-анимация в JSON, сжатая gzip. Чтобы показать стикер, файл распаковывают и отдают Lottie-плееру. Автор GhostGram, экспериментального клиента Telegram на KMP, рассказал на Хабре, как этот путь сломался на Android: с Compottie часть стикеров играла в 2–3 раза быстрее, чем в официальном Telegram, а при 3–4 анимациях на экране кадры рисовались по 200–300 мс. Тест шёл на бюджетном TECNO Spark Go 2024 в release-сборке с R8.
Тюнинг Compottie не помог, и на Android его заменили на Frame Baking — заранее отрисованные кадры:
👉 Airbnb Lottie рисует кадры 260×260 в
Bitmap на Dispatchers.Default, не больше 90 кадров на стикер👉 Кадры лежат в LRU-кэше на 24 MiB, плеер выбирает нужный по времени через
withFrameNanos и рисует drawImage👉 При отмене корутины созданные
Bitmap сразу освобождаютсяНа Desktop остался Compottie. Пики при быстром скролле, пока кадры новых стикеров ещё готовятся, пока не побеждены.
🔗 Статья на Хабре
#Compose #CMP #KMP #Android
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7
На Android Dev Summit Google рассказала, что приходит в Compose в ближайших релизах.
👉 Compose 1.13 скоро выйдет в стабильной версии: Grid и Flexbox для адаптивных раскладок станут стабильными, появятся Progressive Blur и Formatted Text
👉 Navigation 3 1.2 уже стабильна: в ней диплинки и расширенная обработка Predictive Back
👉 AppState (alpha) переносит реактивную модель Compose на слой состояния и помогает сохранять его при смене конфигурации устройства. A2UI для Compose (alpha) показывает ответ агента интерактивным UI из компонентов вашего приложения вместо текста
Compose adaptive skill для агентов теперь переводит раскладки на Grid, FlexBox и mediaQuery и добавляет для десктопа горячие клавиши, курсоры, hover и подсказки.
🔗 Android Developers Blog
#Compose #JetpackCompose #Android
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4❤2👎1
На Android Dev Summit Google показала AppState (alpha). Это набор библиотек androidx.appstate. Главная из них, statestore, хранит Compose-состояние вне UI, то есть вне Activity, и раздаёт его разным частям приложения.
StateStore — обычный класс. Согласно документации, где создавать экземпляр, решает разработчик. Состояние читают по типизированному ключу, а меняют через setState и updateState. Пример ниже собран из тестов и samples в AndroidX:@Serializable
object SampleKey : StateStoreKey<String>("default"), PersistToDataStore
val stateStore = StateStore()
// Compose State<String>: перерисовка при изменении
val state = stateStore.getState(SampleKey)
stateStore.setState(SampleKey, "updated")
stateStore.updateState(SampleKey) { it.uppercase() }
// statestore-datastore: синхронизация с файлом на диске.
// path — путь к файлу, вызов из корутины (suspend), как в официальном sample
stateStore.syncToDataStore(path, CoroutineScope(Dispatchers.IO))
👉
getState возвращает обычный State<T> из Compose👉 Ключ с
autoClearKey сам удаляет своё значение, когда меняется связанный ключ👉 Модуль transform собирает новое состояние из нескольких источников через
transform { } и listener { }Готового способа передать
StateStore в UI, вроде CompositionLocal, в библиотеке пока нет. API в alpha и ещё поменяется.🔗 Android Developers Blog
#Compose #AndroidDev #Jetpack
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👎1
This media is not supported in your browser
VIEW IN TELEGRAM
Prevue — плагин для Claude Code и Codex. Он показывает все
@Preview из файла в браузере без Android Studio и перерисовывает их примерно через секунду после сохранения. Агент видит картинку, сверяет её с макетом или скриншотом и правит код сам.claude plugin marketplace add https://github.com/kakao/prevue.git
claude plugin install prevue@prevue
👉 Клик вместо объяснений: нажали на элемент, и агент получил файл и строку
👉 Интерактивный режим: нажатия, анимации, разные устройства, включая складные
👉 Легче IDE: на nowinandroid 1,4 ГБ памяти против 8,1 ГБ у Android Studio, можно держать по копии на каждый worktree
В отличие от Spyglass, Prevue работает с обычными Android-превью.
⚠️ Нужны JDK 21+ и macOS, замеры от авторов.
🔗 GitHub
#Compose #AI #ClaudeCode
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14👎3