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