diff --git a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/presentation/list/VideoScreen.kt b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/presentation/list/VideoScreen.kt index 6ff1d7b..d0648e7 100644 --- a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/presentation/list/VideoScreen.kt +++ b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/presentation/list/VideoScreen.kt @@ -150,18 +150,14 @@ fun VideosInfo( val requester = remember { FocusRequester() } val blur = LocalBlurState.current val gridState = rememberLazyGridState() - - Box(modifier = Modifier.fillMaxSize()) { + Box(modifier = Modifier.fillMaxSize().padding(4.dp)) { if (items.isNotEmpty()) { LazyVerticalGrid( columns = GridCells.Adaptive(minSize = 130.dp), - modifier = Modifier - .fillMaxSize() - .padding(8.dp) - .applyBlurSource(blur), + modifier = Modifier.fillMaxSize().applyBlurSource(blur), contentPadding = paddingValues, - verticalArrangement = Arrangement.spacedBy(12.dp), - horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalArrangement = Arrangement.spacedBy(4.dp), + horizontalArrangement = Arrangement.spacedBy(4.dp), state = gridState ) { itemsIndexed( @@ -181,8 +177,6 @@ fun VideosInfo( VideosNotFound(emptyResource) } } - - // Мягкий фокус без withFrameNanos, реагирующий на появление данных LaunchedEffect(items.isNotEmpty()) { if (items.isNotEmpty()) { requester.requestFocus() @@ -199,21 +193,18 @@ fun Poster( ) { var isFocused by remember { mutableStateOf(false) } - // Анимируем увеличение карточки при фокусе (эффект для ТВ) val scale by animateFloatAsState( - targetValue = if (isFocused) 1.08f else 1.0f, + targetValue = if (isFocused) 1.0f else 0.92f, animationSpec = spring(stiffness = Spring.StiffnessMediumLow), label = "scale" ) - // Плавная анимация цвета обводки val borderColor by animateColorAsState( targetValue = if (isFocused) MaterialTheme.colorScheme.primary else Color.Transparent, animationSpec = tween(200), label = "borderColor" ) - // Плавная анимация толщины обводки val borderWidth by animateDpAsState( targetValue = if (isFocused) 3.dp else 0.dp, animationSpec = tween(200), @@ -222,9 +213,8 @@ fun Poster( Box( modifier = modifier - .aspectRatio(0.7f) // Стандартное кинематографическое соотношение для постеров + .aspectRatio(0.7f) .graphicsLayer { - // Применяем масштаб и скругление на уровне слоя (работает максимально быстро) scaleX = scale scaleY = scale clip = true @@ -238,27 +228,22 @@ fun Poster( ) .clickable(onClick = onClick) ) { - // Картинка постера Image( painter = rememberImagePainter(imageUrl), contentDescription = null, contentScale = ContentScale.Crop, modifier = Modifier.fillMaxSize() ) - - // Оптимизированный затемняющий градиент (снизу вверх) Box( modifier = Modifier .fillMaxSize() .background( Brush.verticalGradient( - 0.4f to Color.Transparent, // До 40% высоты прозрачно - 1.0f to Color.Black.copy(alpha = 0.85f) // К низу плотное затемнение + 0.4f to Color.Transparent, + 1.0f to Color.Black.copy(alpha = 0.85f) ) ) ) - - // Текст названия фильма/сериала Text( text = label, style = MaterialTheme.typography.bodyMedium.copy( diff --git a/libs/ui/src/androidMain/kotlin/ru/shadowsparky/ui/components/InsetLazyColumn.android.kt b/libs/ui/src/androidMain/kotlin/ru/shadowsparky/ui/components/InsetLazyColumn.android.kt index b37399e..c50326c 100644 --- a/libs/ui/src/androidMain/kotlin/ru/shadowsparky/ui/components/InsetLazyColumn.android.kt +++ b/libs/ui/src/androidMain/kotlin/ru/shadowsparky/ui/components/InsetLazyColumn.android.kt @@ -4,11 +4,14 @@ import android.app.UiModeManager import android.content.Context import android.content.res.Configuration import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext @Composable actual fun isTv(): Boolean { val context = LocalContext.current - val uiModeManager = context.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager - return uiModeManager.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION + return remember(context) { + val uiModeManager = context.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager + uiModeManager.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION + } } diff --git a/libs/ui/src/commonMain/kotlin/ru/shadowsparky/ui/BaseScreen.kt b/libs/ui/src/commonMain/kotlin/ru/shadowsparky/ui/BaseScreen.kt index cdcd2b5..5d60726 100644 --- a/libs/ui/src/commonMain/kotlin/ru/shadowsparky/ui/BaseScreen.kt +++ b/libs/ui/src/commonMain/kotlin/ru/shadowsparky/ui/BaseScreen.kt @@ -17,7 +17,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialExpressiveTheme -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationRail @@ -161,10 +160,7 @@ private fun ExpandedContent( val bottomPadding = values.calculateBottomPadding() val endPadding = values.calculateEndPadding(LayoutDirection.Ltr) Row(modifier = Modifier.fillMaxSize()) { - NavigationRail( - modifier = Modifier.padding(start = 4.dp, end = 4.dp, top = topPadding), - containerColor = MaterialTheme.colorScheme.surfaceContainerLow - ) { + NavigationRail(modifier = Modifier.padding(start = 4.dp, end = 4.dp, top = topPadding)) { navigationEntries.forEach { entry -> NavigationRailItem( selected = currentRoute == entry.route, diff --git a/libs/ui/src/commonMain/kotlin/ru/shadowsparky/ui/components/AlertContent.kt b/libs/ui/src/commonMain/kotlin/ru/shadowsparky/ui/components/AlertContent.kt index 2b82d0f..5b5ea11 100644 --- a/libs/ui/src/commonMain/kotlin/ru/shadowsparky/ui/components/AlertContent.kt +++ b/libs/ui/src/commonMain/kotlin/ru/shadowsparky/ui/components/AlertContent.kt @@ -27,7 +27,7 @@ fun AlertContent( @Composable fun BaseDialogLayout() { Column( - modifier = Modifier.padding(8.dp), + modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(6.dp) ) { title?.let { @@ -51,9 +51,10 @@ fun AlertContent( ) { Surface( shape = MaterialTheme.shapes.extraLarge, - color = MaterialTheme.colorScheme.surface, - tonalElevation = 6.dp - ) { BaseDialogLayout() } + color = MaterialTheme.colorScheme.surface + ) { + BaseDialogLayout() + } } } else { ModalBottomSheet(