package dev.darkpyonix.composerust.design
// A copy of GlassFill.kt from the liquid-glass module of the design-systems
// project, with the package changed and SurfaceMaterial taken from this module rather
// than from that project's core. That project is published on its own and must never
// depend on the renderer, so the material exists twice deliberately. Copies run in one
// direction: change the design systems file first, then bring the change here.
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
/**
* The one decision a glass surface makes before it draws: translucent, or opaque.
*
* It lives apart from the modifier that uses it because it is where two promises are
* kept, and a promise that can only be checked by looking at a screen is not a promise.
* Given the same inputs this returns the same colour, so a test can state the rule
* directly: reduced transparency takes the opaque path, a build without blur takes the
* opaque path, and the colour it takes is the one whose contrast was guaranteed when the
* material was built.
*
* Translucency without blur is the case worth naming. It is not a milder version of the
* effect; it is the same loss of contrast with none of the separation that made the loss
* worth it, so a surface that would blur and cannot has no reason to stay see-through.
*/
fun glassFill(
material: SurfaceMaterial,
reduceTransparency: Boolean,
blurAvailable: Boolean,
depth: Int = 0,
windowActive: Boolean = true,
): Color {
// An opaque material has one colour and neither setting changes it. Taking any
// SurfaceMaterial rather than only the glass case means a caller styling a surface
// asks the same question whichever system is active, instead of having to know which
// of them uses glass before it can ask.
if (material !is SurfaceMaterial.Glass) return (material as SurfaceMaterial.Opaque).color
val resolved = material.atDepth(depth)
return if (drawsAsGlass(reduceTransparency, blurAvailable, windowActive)) {
resolved.tint.copy(alpha = resolved.tintAlpha)
} else {
resolved.fallback
}
}
/** Whether these conditions leave a glass material drawing as glass. */
fun drawsAsGlass(
reduceTransparency: Boolean,
blurAvailable: Boolean,
windowActive: Boolean = true,
): Boolean = !reduceTransparency && blurAvailable && windowActive
/**
* The blur radius these conditions actually call for.
*
* Zero unless the surface is drawing as glass. Turning transparency off, or running where
* blur is unavailable, has to remove the render pass and not only the look: blurring a
* backdrop nobody can see through is pure cost, paid every frame, by the reader who asked
* for less of it.
*/
fun glassBlurRadius(
material: SurfaceMaterial,
reduceTransparency: Boolean,
blurAvailable: Boolean,
windowActive: Boolean = true,
): Dp = if (
material is SurfaceMaterial.Glass &&
drawsAsGlass(reduceTransparency, blurAvailable, windowActive)
) {
material.blurRadius
} else {
0.dp
}