feat: Implement navigation bar visibility handling based on navigation mode
This commit is contained in:
@@ -228,11 +228,9 @@ fun ChatsListScreen(
|
|||||||
insetsController.isAppearanceLightStatusBars = !isDarkTheme
|
insetsController.isAppearanceLightStatusBars = !isDarkTheme
|
||||||
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||||
|
|
||||||
// Navigation bar — keep visible, match theme
|
// Navigation bar: показываем только если есть нативные кнопки
|
||||||
insetsController.show(
|
com.rosetta.messenger.ui.utils.NavigationModeUtils
|
||||||
androidx.core.view.WindowInsetsCompat.Type.navigationBars()
|
.applyNavigationBarVisibility(insetsController, context, isDarkTheme)
|
||||||
)
|
|
||||||
insetsController.isAppearanceLightNavigationBars = !isDarkTheme
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,8 +104,8 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio
|
|||||||
ChatsUiState()
|
ChatsUiState()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Загрузка
|
// Загрузка (🔥 true по умолчанию — skeleton на первом кадре, чтобы не мигало empty→skeleton→empty)
|
||||||
private val _isLoading = MutableStateFlow(false)
|
private val _isLoading = MutableStateFlow(true)
|
||||||
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
|
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
|
||||||
|
|
||||||
private val TAG = "ChatsListVM"
|
private val TAG = "ChatsListVM"
|
||||||
@@ -114,6 +114,8 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio
|
|||||||
fun setAccount(publicKey: String, privateKey: String) {
|
fun setAccount(publicKey: String, privateKey: String) {
|
||||||
val setAccountStart = System.currentTimeMillis()
|
val setAccountStart = System.currentTimeMillis()
|
||||||
if (currentAccount == publicKey) {
|
if (currentAccount == publicKey) {
|
||||||
|
// 🔥 Сбрасываем skeleton если он ещё показан (при повторном заходе)
|
||||||
|
if (_isLoading.value) _isLoading.value = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -212,9 +212,17 @@ fun ImageEditorScreen(
|
|||||||
onDispose {
|
onDispose {
|
||||||
if (window == null || insetsController == null) return@onDispose
|
if (window == null || insetsController == null) return@onDispose
|
||||||
window.statusBarColor = originalStatusBarColor
|
window.statusBarColor = originalStatusBarColor
|
||||||
window.navigationBarColor = originalNavigationBarColor
|
|
||||||
insetsController.isAppearanceLightStatusBars = originalLightStatusBars
|
insetsController.isAppearanceLightStatusBars = originalLightStatusBars
|
||||||
|
|
||||||
|
// Navigation bar: восстанавливаем только если есть нативные кнопки
|
||||||
|
if (com.rosetta.messenger.ui.utils.NavigationModeUtils.hasNativeNavigationBar(context)) {
|
||||||
|
window.navigationBarColor = originalNavigationBarColor
|
||||||
insetsController.isAppearanceLightNavigationBars = originalLightNavigationBars
|
insetsController.isAppearanceLightNavigationBars = originalLightNavigationBars
|
||||||
|
} else {
|
||||||
|
insetsController.hide(androidx.core.view.WindowInsetsCompat.Type.navigationBars())
|
||||||
|
insetsController.systemBarsBehavior =
|
||||||
|
androidx.core.view.WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1573,9 +1581,17 @@ fun MultiImageEditorScreen(
|
|||||||
onDispose {
|
onDispose {
|
||||||
if (window == null || insetsController == null) return@onDispose
|
if (window == null || insetsController == null) return@onDispose
|
||||||
window.statusBarColor = originalStatusBarColor
|
window.statusBarColor = originalStatusBarColor
|
||||||
window.navigationBarColor = originalNavigationBarColor
|
|
||||||
insetsController.isAppearanceLightStatusBars = originalLightStatusBars
|
insetsController.isAppearanceLightStatusBars = originalLightStatusBars
|
||||||
|
|
||||||
|
// Navigation bar: восстанавливаем только если есть нативные кнопки
|
||||||
|
if (com.rosetta.messenger.ui.utils.NavigationModeUtils.hasNativeNavigationBar(context)) {
|
||||||
|
window.navigationBarColor = originalNavigationBarColor
|
||||||
insetsController.isAppearanceLightNavigationBars = originalLightNavigationBars
|
insetsController.isAppearanceLightNavigationBars = originalLightNavigationBars
|
||||||
|
} else {
|
||||||
|
insetsController.hide(androidx.core.view.WindowInsetsCompat.Type.navigationBars())
|
||||||
|
insetsController.systemBarsBehavior =
|
||||||
|
androidx.core.view.WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,9 +139,17 @@ fun InAppCameraScreen(
|
|||||||
onDispose {
|
onDispose {
|
||||||
if (window == null || insetsController == null) return@onDispose
|
if (window == null || insetsController == null) return@onDispose
|
||||||
window.statusBarColor = originalStatusBarColor
|
window.statusBarColor = originalStatusBarColor
|
||||||
window.navigationBarColor = originalNavigationBarColor
|
|
||||||
insetsController.isAppearanceLightStatusBars = originalLightStatusBars
|
insetsController.isAppearanceLightStatusBars = originalLightStatusBars
|
||||||
|
|
||||||
|
// Navigation bar: восстанавливаем только если есть нативные кнопки
|
||||||
|
if (com.rosetta.messenger.ui.utils.NavigationModeUtils.hasNativeNavigationBar(context)) {
|
||||||
|
window.navigationBarColor = originalNavigationBarColor
|
||||||
insetsController.isAppearanceLightNavigationBars = originalLightNavigationBars
|
insetsController.isAppearanceLightNavigationBars = originalLightNavigationBars
|
||||||
|
} else {
|
||||||
|
insetsController.hide(androidx.core.view.WindowInsetsCompat.Type.navigationBars())
|
||||||
|
insetsController.systemBarsBehavior =
|
||||||
|
androidx.core.view.WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ import androidx.compose.ui.draw.clip
|
|||||||
import androidx.compose.ui.draw.drawWithContent
|
import androidx.compose.ui.draw.drawWithContent
|
||||||
import androidx.compose.ui.draw.rotate
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.draw.scale
|
import androidx.compose.ui.draw.scale
|
||||||
|
import androidx.compose.ui.geometry.CornerRadius
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.geometry.Size
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.Path
|
import androidx.compose.ui.graphics.Path
|
||||||
@@ -43,9 +45,12 @@ import androidx.compose.ui.unit.Dp
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import com.airbnb.lottie.compose.*
|
import com.airbnb.lottie.compose.*
|
||||||
import com.rosetta.messenger.R
|
import com.rosetta.messenger.R
|
||||||
import com.rosetta.messenger.ui.theme.*
|
import com.rosetta.messenger.ui.theme.*
|
||||||
|
import com.rosetta.messenger.ui.utils.NavigationModeUtils
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.acos
|
import kotlin.math.acos
|
||||||
@@ -154,8 +159,12 @@ fun OnboardingScreen(
|
|||||||
val window = (view.context as android.app.Activity).window
|
val window = (view.context as android.app.Activity).window
|
||||||
val insetsController = WindowCompat.getInsetsController(window, view)
|
val insetsController = WindowCompat.getInsetsController(window, view)
|
||||||
insetsController.isAppearanceLightStatusBars = !isDarkTheme
|
insetsController.isAppearanceLightStatusBars = !isDarkTheme
|
||||||
insetsController.isAppearanceLightNavigationBars = !isDarkTheme
|
|
||||||
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||||
|
|
||||||
|
// Navigation bar: показываем только если есть нативные кнопки
|
||||||
|
NavigationModeUtils.applyNavigationBarVisibility(
|
||||||
|
insetsController, view.context, isDarkTheme
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,8 +172,16 @@ fun OnboardingScreen(
|
|||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
if (!view.isInEditMode) {
|
if (!view.isInEditMode) {
|
||||||
val window = (view.context as android.app.Activity).window
|
val window = (view.context as android.app.Activity).window
|
||||||
|
val insetsController = WindowCompat.getInsetsController(window, view)
|
||||||
|
if (NavigationModeUtils.hasNativeNavigationBar(view.context)) {
|
||||||
window.navigationBarColor =
|
window.navigationBarColor =
|
||||||
if (isDarkTheme) 0xFF1E1E1E.toInt() else 0xFFFFFFFF.toInt()
|
if (isDarkTheme) 0xFF1E1E1E.toInt() else 0xFFFFFFFF.toInt()
|
||||||
|
} else {
|
||||||
|
// Жестовая навигация — прячем бар
|
||||||
|
insetsController.hide(WindowInsetsCompat.Type.navigationBars())
|
||||||
|
insetsController.systemBarsBehavior =
|
||||||
|
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,7 +702,7 @@ fun GooeyPagerIndicator(
|
|||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
dotRadius: Dp = 2.8.dp,
|
dotRadius: Dp = 2.8.dp,
|
||||||
dotSpacing: Dp = 12.dp,
|
dotSpacing: Dp = 12.dp,
|
||||||
indicatorHeight: Dp = 18.dp
|
indicatorHeight: Dp = 18.dp,
|
||||||
) {
|
) {
|
||||||
if (pageCount <= 0) return
|
if (pageCount <= 0) return
|
||||||
|
|
||||||
@@ -699,6 +716,17 @@ fun GooeyPagerIndicator(
|
|||||||
val trackWidth = if (pageCount > 1) spacing * (pageCount - 1) else 0f
|
val trackWidth = if (pageCount > 1) spacing * (pageCount - 1) else 0f
|
||||||
val startX = (size.width - trackWidth) / 2f
|
val startX = (size.width - trackWidth) / 2f
|
||||||
|
|
||||||
|
if (pageCount > 1) {
|
||||||
|
val trackInset = baseRadius * 0.75f
|
||||||
|
val trackHeight = baseRadius * 0.45f
|
||||||
|
drawRoundRect(
|
||||||
|
color = unselectedColor.copy(alpha = 0.14f),
|
||||||
|
topLeft = Offset(startX - trackInset, centerY - trackHeight / 2f),
|
||||||
|
size = Size(trackWidth + trackInset * 2f, trackHeight),
|
||||||
|
cornerRadius = CornerRadius(trackHeight, trackHeight)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val rawPosition =
|
val rawPosition =
|
||||||
(pagerState.currentPage + pagerState.currentPageOffsetFraction)
|
(pagerState.currentPage + pagerState.currentPageOffsetFraction)
|
||||||
.coerceIn(0f, (pageCount - 1).toFloat())
|
.coerceIn(0f, (pageCount - 1).toFloat())
|
||||||
@@ -706,35 +734,77 @@ fun GooeyPagerIndicator(
|
|||||||
|
|
||||||
repeat(pageCount) { index ->
|
repeat(pageCount) { index ->
|
||||||
val center = Offset(startX + index * spacing, centerY)
|
val center = Offset(startX + index * spacing, centerY)
|
||||||
drawCircle(color = unselectedColor, radius = baseRadius, center = center)
|
val distanceToActive = abs(rawPosition - index)
|
||||||
|
val influence = (1f - distanceToActive / 1.25f).coerceIn(0f, 1f)
|
||||||
|
val dotScale = 0.88f + influence * 0.16f
|
||||||
|
val dotAlpha = 0.35f + influence * 0.35f
|
||||||
|
drawCircle(
|
||||||
|
color = unselectedColor.copy(alpha = unselectedColor.alpha * dotAlpha),
|
||||||
|
radius = baseRadius * dotScale,
|
||||||
|
center = center
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val from = floor(rawPosition.toDouble()).toInt().coerceIn(0, pageCount - 1)
|
val from = floor(rawPosition.toDouble()).toInt().coerceIn(0, pageCount - 1)
|
||||||
val to = ceil(rawPosition.toDouble()).toInt().coerceIn(0, pageCount - 1)
|
val to = ceil(rawPosition.toDouble()).toInt().coerceIn(0, pageCount - 1)
|
||||||
val transition = rawPosition - from
|
val transition = rawPosition - from
|
||||||
val stretch = (1f - abs(transition - 0.5f) * 2f).coerceIn(0f, 1f)
|
val stretch = (1f - abs(transition - 0.5f) * 2f).coerceIn(0f, 1f)
|
||||||
val activeRadius = baseRadius * (1.08f + stretch * 0.34f)
|
val activeRadius = baseRadius * (1.05f + stretch * 0.3f)
|
||||||
|
|
||||||
|
var metaballPath: Path? = null
|
||||||
|
var anchorCenter: Offset? = null
|
||||||
|
var anchorRadius = 0f
|
||||||
|
|
||||||
if (from != to) {
|
if (from != to) {
|
||||||
val anchorIndex = if (transition < 0.5f) from else to
|
val anchorIndex = if (transition < 0.5f) from else to
|
||||||
val anchorCenter = Offset(startX + anchorIndex * spacing, centerY)
|
anchorCenter = Offset(startX + anchorIndex * spacing, centerY)
|
||||||
val anchorRadius = baseRadius * (1.0f - stretch * 0.1f)
|
anchorRadius = baseRadius * (0.86f + (1f - stretch) * 0.2f)
|
||||||
|
|
||||||
|
metaballPath =
|
||||||
createMetaballPath(
|
createMetaballPath(
|
||||||
c1 = activeCenter,
|
c1 = activeCenter,
|
||||||
r1 = activeRadius,
|
r1 = activeRadius,
|
||||||
c2 = anchorCenter,
|
c2 = anchorCenter,
|
||||||
r2 = anchorRadius,
|
r2 = anchorRadius,
|
||||||
maxDistance = spacing * 1.28f,
|
maxDistance = spacing * 1.36f,
|
||||||
viscosity = 0.32f,
|
viscosity = 0.36f + stretch * 0.12f,
|
||||||
handleSize = 2.25f
|
handleSize = 2.45f
|
||||||
)
|
)
|
||||||
?.let { path ->
|
|
||||||
drawPath(path = path, color = selectedColor.copy(alpha = 0.92f))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drawCircle(
|
||||||
|
color = selectedColor.copy(alpha = 0.18f),
|
||||||
|
radius = activeRadius * 2.2f,
|
||||||
|
center = activeCenter
|
||||||
|
)
|
||||||
|
if (anchorCenter != null) {
|
||||||
|
drawCircle(
|
||||||
|
color = selectedColor.copy(alpha = 0.1f + stretch * 0.1f),
|
||||||
|
radius = anchorRadius * 1.9f,
|
||||||
|
center = anchorCenter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
metaballPath?.let { path ->
|
||||||
|
drawPath(path = path, color = selectedColor.copy(alpha = 0.2f + stretch * 0.12f))
|
||||||
|
}
|
||||||
|
if (anchorCenter != null) {
|
||||||
|
drawCircle(
|
||||||
|
color = selectedColor.copy(alpha = 0.78f),
|
||||||
|
radius = anchorRadius,
|
||||||
|
center = anchorCenter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
metaballPath?.let { path -> drawPath(path = path, color = selectedColor.copy(alpha = 0.92f)) }
|
||||||
drawCircle(color = selectedColor, radius = activeRadius, center = activeCenter)
|
drawCircle(color = selectedColor, radius = activeRadius, center = activeCenter)
|
||||||
|
drawCircle(
|
||||||
|
color = Color.White.copy(alpha = 0.28f),
|
||||||
|
radius = activeRadius * 0.38f,
|
||||||
|
center =
|
||||||
|
Offset(
|
||||||
|
x = activeCenter.x - activeRadius * 0.28f,
|
||||||
|
y = activeCenter.y - activeRadius * 0.32f
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import androidx.compose.ui.graphics.toArgb
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
|
import com.rosetta.messenger.ui.utils.NavigationModeUtils
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
private val DarkColorScheme = darkColorScheme(
|
private val DarkColorScheme = darkColorScheme(
|
||||||
@@ -63,14 +64,17 @@ fun RosettaAndroidTheme(
|
|||||||
else -> LightColorScheme
|
else -> LightColorScheme
|
||||||
}
|
}
|
||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
|
val context = LocalContext.current
|
||||||
if (!view.isInEditMode) {
|
if (!view.isInEditMode) {
|
||||||
SideEffect {
|
SideEffect {
|
||||||
val window = (view.context as android.app.Activity).window
|
val window = (view.context as android.app.Activity).window
|
||||||
|
val insetsController = WindowCompat.getInsetsController(window, view)
|
||||||
// Make status bar transparent for wave animation overlay
|
// Make status bar transparent for wave animation overlay
|
||||||
window.statusBarColor = AndroidColor.TRANSPARENT
|
window.statusBarColor = AndroidColor.TRANSPARENT
|
||||||
// Navigation bar color is managed by OnboardingScreen for smooth transition
|
insetsController.isAppearanceLightStatusBars = !darkTheme
|
||||||
// Don't change it here to avoid instant color change
|
|
||||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme
|
// Navigation bar: показываем только если есть нативные кнопки
|
||||||
|
NavigationModeUtils.applyNavigationBarVisibility(insetsController, context, darkTheme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package com.rosetta.messenger.ui.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Утилита для определения типа системной навигации.
|
||||||
|
*
|
||||||
|
* Android поддерживает 3 режима:
|
||||||
|
* - 0 = 3-button navigation (нативные кнопки: Back, Home, Recents)
|
||||||
|
* - 1 = 2-button navigation (кнопка Home + жест назад)
|
||||||
|
* - 2 = Gesture navigation (полностью жестовая навигация, без кнопок)
|
||||||
|
*
|
||||||
|
* Если у устройства gesture navigation (2), нижний navigation bar прячем.
|
||||||
|
* Если у устройства кнопочная навигация (0 или 1), показываем navigation bar.
|
||||||
|
*/
|
||||||
|
object NavigationModeUtils {
|
||||||
|
|
||||||
|
private const val NAV_MODE_THREE_BUTTON = 0
|
||||||
|
private const val NAV_MODE_TWO_BUTTON = 1
|
||||||
|
private const val NAV_MODE_GESTURE = 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает текущий режим навигации.
|
||||||
|
* 0 = 3-button, 1 = 2-button, 2 = gesture
|
||||||
|
*/
|
||||||
|
fun getNavigationMode(context: Context): Int {
|
||||||
|
return try {
|
||||||
|
val resId = context.resources.getIdentifier(
|
||||||
|
"config_navBarInteractionMode", "integer", "android"
|
||||||
|
)
|
||||||
|
if (resId > 0) context.resources.getInteger(resId) else NAV_MODE_THREE_BUTTON
|
||||||
|
} catch (_: Exception) {
|
||||||
|
NAV_MODE_THREE_BUTTON
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true если устройство использует жестовую навигацию (без нативных кнопок внизу)
|
||||||
|
*/
|
||||||
|
fun isGestureNavigation(context: Context): Boolean {
|
||||||
|
return getNavigationMode(context) == NAV_MODE_GESTURE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true если у устройства есть нативная панель навигации (3 или 2 кнопки)
|
||||||
|
*/
|
||||||
|
fun hasNativeNavigationBar(context: Context): Boolean {
|
||||||
|
return !isGestureNavigation(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Показывает или прячет navigation bar в зависимости от типа навигации.
|
||||||
|
* - Кнопочная навигация → показываем бар
|
||||||
|
* - Жестовая навигация → прячем бар, свайп снизу временно покажет
|
||||||
|
*/
|
||||||
|
fun applyNavigationBarVisibility(
|
||||||
|
insetsController: WindowInsetsControllerCompat,
|
||||||
|
context: Context,
|
||||||
|
isDarkTheme: Boolean
|
||||||
|
) {
|
||||||
|
if (hasNativeNavigationBar(context)) {
|
||||||
|
// Есть нативные кнопки — показываем навигационный бар
|
||||||
|
insetsController.show(WindowInsetsCompat.Type.navigationBars())
|
||||||
|
insetsController.isAppearanceLightNavigationBars = !isDarkTheme
|
||||||
|
} else {
|
||||||
|
// Жестовая навигация — прячем навигационный бар
|
||||||
|
insetsController.hide(WindowInsetsCompat.Type.navigationBars())
|
||||||
|
insetsController.systemBarsBehavior =
|
||||||
|
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composable-хелпер: запоминает, использует ли устройство жестовую навигацию.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun rememberIsGestureNavigation(): Boolean {
|
||||||
|
val context = LocalContext.current
|
||||||
|
return remember { NavigationModeUtils.isGestureNavigation(context) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composable-хелпер: запоминает, есть ли нативная навигационная панель.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun rememberHasNativeNavigationBar(): Boolean {
|
||||||
|
val context = LocalContext.current
|
||||||
|
return remember { NavigationModeUtils.hasNativeNavigationBar(context) }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user