hide blur in ui module scope

This commit is contained in:
2026-08-08 22:03:49 +03:00
parent 3962ec29da
commit c5a4963eeb
13 changed files with 70 additions and 68 deletions
@@ -51,8 +51,6 @@ import androidx.compose.ui.unit.dp
import com.seiko.imageloader.rememberImagePainter
import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.ui.LocalBlurState
import ru.shadowsparky.ui.applyBlurSource
import ru.shadowsparky.ui.components.ErrorContent
import ru.shadowsparky.ui.components.LazyVerticalGrid
import ru.shadowsparky.ui.components.Loading
@@ -139,13 +137,12 @@ private fun VideosInfo(
onClick: (item: VideoItem) -> Unit
) {
val requester = remember { FocusRequester() }
val blur = LocalBlurState.current
val gridState = rememberLazyGridState()
Box(modifier = Modifier.fillMaxSize()) {
if (items.isNotEmpty()) {
LazyVerticalGrid(
columns = GridCells.Adaptive(minSize = 130.dp),
modifier = Modifier.fillMaxSize().applyBlurSource(blur),
modifier = Modifier.fillMaxSize(),
contentPadding = paddingValues,
verticalArrangement = Arrangement.spacedBy(4.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp),
@@ -68,8 +68,6 @@ import com.seiko.imageloader.rememberImagePainter
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.domain.Clip
import ru.shadowsparky.ui.LocalBlurState
import ru.shadowsparky.ui.applyBlurSource
import ru.shadowsparky.ui.components.BackButton
import ru.shadowsparky.ui.components.ErrorContent
import ru.shadowsparky.ui.components.LazyColumn
@@ -244,13 +242,9 @@ fun DetailsInfo(
onWatchClicked: () -> Unit
) {
val requester = remember { FocusRequester() }
val blur = LocalBlurState.current
val showDetails = rememberSaveable { mutableStateOf(false) }
LazyColumn(
modifier = Modifier.applyBlurSource(blur),
contentPadding = paddingValues
) {
LazyColumn(contentPadding = paddingValues) {
item { Poster(details.poster) }
item { OverviewDescription(details, showDetails) }
item {
@@ -44,8 +44,6 @@ import androidx.compose.ui.unit.dp
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.domain.Clip
import ru.shadowsparky.ui.LocalBlurState
import ru.shadowsparky.ui.applyBlurSource
import ru.shadowsparky.ui.components.BackButton
import ru.shadowsparky.ui.components.ErrorContent
import ru.shadowsparky.ui.components.ExpressiveLazyColumn
@@ -177,10 +175,9 @@ fun EpisodesOverviewList(
buttonText = stringResource(Res.string.retry)
) { loadLinks() }
} else if (episodes != null) {
val blur = LocalBlurState.current
val requester = remember { FocusRequester() }
ExpressiveLazyColumn(
modifier = Modifier.applyBlurSource(blur).fillMaxSize(),
modifier = Modifier.fillMaxSize(),
contentPadding = contentPadding,
content = {
section {
@@ -20,8 +20,6 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.ui.LocalBlurState
import ru.shadowsparky.ui.applyBlurSource
import ru.shadowsparky.ui.components.BackButton
import ru.shadowsparky.ui.components.ErrorContent
import ru.shadowsparky.ui.components.ExpressiveLazyColumn
@@ -68,10 +66,9 @@ fun SeasonsInfo(
paddingValues: PaddingValues,
onClick: (Long) -> Unit
) {
val blur = LocalBlurState.current
val requester = remember { FocusRequester() }
ExpressiveLazyColumn(
Modifier.applyBlurSource(blur).fillMaxWidth(),
Modifier.fillMaxWidth(),
contentPadding = paddingValues,
content = {
section {
@@ -21,7 +21,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.AppBarWithSearch
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
@@ -33,7 +32,6 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldColors
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.rememberSearchBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
@@ -65,11 +63,8 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.ui.LocalBlurState
import ru.shadowsparky.ui.applyBlurEffect
import ru.shadowsparky.ui.applyBlurSource
import ru.shadowsparky.ui.components.AppBarWithSearch
import ru.shadowsparky.ui.components.ExpressiveLazyColumn
import ru.shadowsparky.ui.theme.ComponentDefaults
import ru.shadowsparky.vbox.shared.presentation.BaseMainScreen
import ru.shadowsparky.vbox.shared.presentation.imePaddingInternal
import ru.shadowsparky.vbox.shared.presentation.nav.Route
@@ -157,10 +152,8 @@ fun OldSearchInfo(
) {
val keyboardController = LocalSoftwareKeyboardController.current
val nestedScrollConnection = remember { HideKeyboardConnection { keyboardController } }
val blur = LocalBlurState.current
ExpressiveLazyColumn(
modifier = Modifier.applyBlurSource(blur)
.nestedScroll(nestedScrollConnection)
modifier = Modifier.nestedScroll(nestedScrollConnection)
.imePaddingInternal(),
contentPadding = contentPaddingValues,
content = {
@@ -224,11 +217,7 @@ fun SearchAppBar(
inputFocusRequester.freeFocus()
}
}
val blur = LocalBlurState.current
AppBarWithSearch(
modifier = Modifier.applyBlurEffect(blur),
state = rememberSearchBarState(),
colors = ComponentDefaults.appBarWithSearchDefaults(),
inputField = {
TextField(
value = textFieldValue,
@@ -287,11 +276,7 @@ fun AppBarWithSearch(
actions: @Composable RowScope.() -> Unit = {},
onBack: (() -> Unit)
) {
val blur = LocalBlurState.current
AppBarWithSearch(
modifier = Modifier.applyBlurEffect(blur),
state = rememberSearchBarState(),
colors = ComponentDefaults.appBarWithSearchDefaults(),
actions = { actions(this) },
navigationIcon = {},
inputField = {
@@ -21,8 +21,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.ui.LocalBlurState
import ru.shadowsparky.ui.applyBlurSource
import ru.shadowsparky.ui.components.ExpressiveLazyColumn
import ru.shadowsparky.ui.components.SwitchPreference
import ru.shadowsparky.ui.components.TextPreference
@@ -33,10 +31,8 @@ fun SettingsContent(comp: SettingsComponent, paddingValues: PaddingValues) {
val servAddr by comp.serverInfo.collectAsState(null)
val tokenInfo by comp.tokenInfo.collectAsState(null)
val externalPlayerState by comp.externalPlayerState.collectAsState(null)
val blur = LocalBlurState.current
val requester = remember { FocusRequester() }
ExpressiveLazyColumn(
modifier = Modifier.applyBlurSource(blur),
contentPadding = paddingValues,
content = {
section {
@@ -66,9 +66,6 @@ import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.chat.domain.ChatRoles
import ru.shadowsparky.chat.domain.Message
import ru.shadowsparky.chat.domain.TextToken
import ru.shadowsparky.ui.BlurState
import ru.shadowsparky.ui.LocalBlurState
import ru.shadowsparky.ui.applyBlurSource
import ru.shadowsparky.ui.components.AlertContent
import ru.shadowsparky.ui.components.LazyColumn
import ru.shadowsparky.ui.components.Loading
@@ -112,7 +109,6 @@ fun ChatContent(
is ChatState.Data -> {
ChatContent(
contentPadding = PaddingValues(top = paddingValues.calculateTopPadding()),
LocalBlurState.current,
state = state,
onParseMessage = { component.parseMessage(it) },
onClickLink = { component.onLinkClicked(it) },
@@ -127,7 +123,6 @@ fun ChatContent(
@Composable
private fun ChatContent(
contentPadding: PaddingValues,
blurState: BlurState?,
state: ChatState.Data,
onParseMessage: (String) -> List<TextToken>,
onClickLink: (String) -> Unit,
@@ -150,8 +145,7 @@ private fun ChatContent(
Column(modifier = Modifier.fillMaxSize()) {
LazyColumn(
state = listState,
modifier = Modifier.applyBlurSource(blurState)
.focusRequester(listFocusRequester)
modifier = Modifier.focusRequester(listFocusRequester)
.weight(1f)
.fillMaxWidth(),
contentPadding = contentPadding,
@@ -122,7 +122,6 @@ private fun <T : Route> BottomBar(
currentRoute: T?,
onSelectNavigation: ((T) -> Unit)?
) {
val blurState = LocalBlurState.current
navigationEntries?.let { entries ->
Box(
modifier = Modifier
@@ -140,7 +139,7 @@ private fun <T : Route> BottomBar(
) {
NavigationBar(
containerColor = ComponentDefaults.navBarContentColor(),
modifier = ComponentDefaults.roundedClip().applyBlurEffect(blurState)
modifier = ComponentDefaults.roundedClip().blurEffect()
) {
entries.forEach { entry ->
NavigationBarItem(
@@ -13,33 +13,30 @@ import dev.chrisbanes.haze.materials.HazeMaterials
import dev.chrisbanes.haze.rememberHazeState
import ru.shadowsparky.ui.components.isTv
private const val BLUR_ENABLED = true
val LocalBlurState = compositionLocalOf<BlurState?> { null }
internal val LocalBlurState = compositionLocalOf<BlurState?> { null }
@Composable
internal fun isBlurEnabled(): Boolean {
return BLUR_ENABLED && !isTv()
}
internal fun isBlurEnabled(): Boolean = !isTv()
@Composable
fun rememberBlurState(): BlurState? {
internal fun rememberBlurState(): BlurState? {
if (!isBlurEnabled()) return null
val hazeState = rememberHazeState()
return remember(hazeState) { BlurState(hazeState) }
}
fun Modifier.applyBlurSource(state: BlurState?): Modifier {
@Composable
internal fun Modifier.blurSource(state: BlurState? = LocalBlurState.current): Modifier {
state ?: return this
return hazeSource(state.hazeState)
}
@OptIn(ExperimentalHazeMaterialsApi::class)
@Composable
fun Modifier.applyBlurEffect(state: BlurState?): Modifier {
internal fun Modifier.blurEffect(state: BlurState? = LocalBlurState.current): Modifier {
state ?: return this
return hazeEffect(state.hazeState, HazeMaterials.thin())
}
@Stable
class BlurState(internal val hazeState: HazeState)
internal class BlurState(internal val hazeState: HazeState)
@@ -0,0 +1,49 @@
package ru.shadowsparky.ui.components
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.material3.AppBarWithSearchColors
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.SearchBarDefaults
import androidx.compose.material3.SearchBarScrollBehavior
import androidx.compose.material3.SearchBarState
import androidx.compose.material3.rememberSearchBarState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp
import ru.shadowsparky.ui.blurEffect
import ru.shadowsparky.ui.theme.ComponentDefaults
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppBarWithSearch(
inputField: @Composable () -> Unit,
modifier: Modifier = Modifier,
state: SearchBarState = rememberSearchBarState(),
navigationIcon: @Composable (() -> Unit)? = null,
actions: @Composable (RowScope.() -> Unit)? = null,
shape: Shape = SearchBarDefaults.inputFieldShape,
colors: AppBarWithSearchColors = ComponentDefaults.appBarWithSearchDefaults(),
tonalElevation: Dp = SearchBarDefaults.TonalElevation,
shadowElevation: Dp = SearchBarDefaults.ShadowElevation,
contentPadding: PaddingValues = SearchBarDefaults.AppBarContentPadding,
windowInsets: WindowInsets = SearchBarDefaults.windowInsets,
scrollBehavior: SearchBarScrollBehavior? = null,
) {
androidx.compose.material3.AppBarWithSearch(
state,
inputField,
modifier.blurEffect(),
navigationIcon,
actions,
shape,
colors,
tonalElevation,
shadowElevation,
contentPadding,
windowInsets,
scrollBehavior
)
}
@@ -14,8 +14,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import ru.shadowsparky.ui.LocalBlurState
import ru.shadowsparky.ui.applyBlurSource
import ru.shadowsparky.ui.blurSource
@Composable
expect fun isTv(): Boolean
@@ -128,7 +127,7 @@ fun LazyColumn(
if (isTv) {
modifier.padding(contentPadding)
} else {
modifier.applyBlurSource(LocalBlurState.current)
modifier.blurSource()
},
state,
if (isTv) PaddingValues(0.dp) else contentPadding,
@@ -14,8 +14,7 @@ import androidx.compose.foundation.rememberOverscrollEffect
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import ru.shadowsparky.ui.LocalBlurState
import ru.shadowsparky.ui.applyBlurSource
import ru.shadowsparky.ui.blurSource
@Composable
fun LazyVerticalGrid(
@@ -38,7 +37,7 @@ fun LazyVerticalGrid(
if (isTv) {
modifier.padding(contentPadding)
} else {
modifier.applyBlurSource(LocalBlurState.current)
modifier.blurSource()
},
state,
if (isTv) PaddingValues(0.dp) else contentPadding,
@@ -11,8 +11,7 @@ import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import ru.shadowsparky.ui.LocalBlurState
import ru.shadowsparky.ui.applyBlurEffect
import ru.shadowsparky.ui.blurEffect
import ru.shadowsparky.ui.theme.ComponentDefaults
@OptIn(ExperimentalMaterial3Api::class)
@@ -30,7 +29,7 @@ fun TopAppBar(
) {
TopAppBar(
title = title,
modifier = modifier.applyBlurEffect(LocalBlurState.current),
modifier = modifier.blurEffect(),
navigationIcon = navigationIcon,
actions = actions,
expandedHeight = expandedHeight,