Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
Expand Down Expand Up @@ -285,6 +286,73 @@ fun ContentAtEdges(visualEffect: BlurVisualEffect) {
}
}

/**
* Test content for issue #717: verifies that haze effect follows a parent's graphicsLayer rotation.
* Both the hazeSource and hazeEffect are inside the same rotated parent.
*/
@Composable
fun ParentRotatedContent(
visualEffect: BlurVisualEffect,
rotationZ: Float = 0f,
positionStrategy: HazePositionStrategy = HazePositionStrategy.Auto,
) {
val hazeState = rememberHazeState(positionStrategy = positionStrategy)

Box(modifier = Modifier.fillMaxSize()) {
// Background gradient as a haze source (not rotated)
Spacer(
modifier = Modifier
.hazeSource(hazeState)
.fillMaxSize()
.background(
brush = Brush.verticalGradient(
colors = listOf(Color.Red, Color.Cyan, Color.Blue, Color.Magenta, Color.Red),
),
),
)

// A card-like container with graphicsLayer transforms applied to the PARENT,
// wrapping both an image (hazeSource) and a text overlay (hazeEffect).
Box(
modifier = Modifier
.align(Alignment.Center)
.graphicsLayer {
this.rotationZ = rotationZ
scaleX = 1.25f
scaleY = 1.25f
}
.size(width = 250.dp, height = 350.dp)
.clip(RoundedCornerShape(16.dp)),
) {
Image(
painter = painterResource(Res.drawable.photo),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.hazeSource(hazeState)
.fillMaxSize(),
)

Box(
modifier = Modifier
.align(Alignment.BottomCenter)
.fillMaxWidth()
.height(80.dp)
.hazeEffect(state = hazeState) {
this.visualEffect = visualEffect
},
) {
Text(
text = "Haze",
color = Color.White,
style = MaterialTheme.typography.headlineSmall,
modifier = Modifier.align(Alignment.Center),
)
}
}
}
}

internal val LoremIpsum by lazy {
"""
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sit amet congue mauris, iaculis accumsan eros. Aliquam pulvinar est ac elit vulputate egestas. Vestibulum consequat libero at sem varius, vitae semper urna rhoncus. Aliquam mollis, ipsum a convallis scelerisque, sem dui consequat leo, in tempor risus est ac mi. Nam vel tellus dolor. Nunc lobortis bibendum fermentum. Mauris sed mollis justo, eu tristique elit. Cras semper augue a tortor tempor, vitae vestibulum eros convallis. Curabitur id justo eget tortor iaculis lobortis. Integer pharetra augue ac elit porta iaculis non vitae libero. Nam eros turpis, suscipit at iaculis vitae, malesuada vel arcu. Donec tincidunt porttitor iaculis. Pellentesque non augue magna. Mauris mattis purus vitae mi maximus, id molestie ipsum facilisis. Donec bibendum gravida dolor nec suscipit. Pellentesque tempus felis iaculis, porta diam sed, tristique tortor.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,59 @@ class HazeScreenshotTest : ScreenshotTest() {
captureRoot("bottom")
}

/**
* Test for issue #717: verifies haze effect follows a parent's graphicsLayer rotation
* using [HazePositionStrategy.Local].
*/
@Test
fun parentRotation() {
parentRotationTest(HazePositionStrategy.Local)
}

/**
* Same as [parentRotation] but using [HazePositionStrategy.Screen] to compare behavior.
*/
@Test
fun parentRotation_screenStrategy() {
parentRotationTest(HazePositionStrategy.Screen)
}

private fun parentRotationTest(positionStrategy: HazePositionStrategy) = runScreenshotTest {
var rotationZ by mutableStateOf(0f)
val blurVisualEffect = BlurVisualEffect().apply {
colorEffects = listOf(DefaultTint)
blurRadius = 8.dp
}

setContent {
ScreenshotTheme {
ParentRotatedContent(
visualEffect = blurVisualEffect,
rotationZ = rotationZ,
positionStrategy = positionStrategy,
)
}
}

captureRoot("0deg")

rotationZ = 15f
waitForIdle()
captureRoot("15deg")

rotationZ = 45f
waitForIdle()
captureRoot("45deg")

rotationZ = 90f
waitForIdle()
captureRoot("90deg")

rotationZ = 180f
waitForIdle()
captureRoot("180deg")
}

@Test
fun edges() = runScreenshotTest {
val blurVisualEffect = BlurVisualEffect().apply {
Expand Down
Loading