An attentive viewer has probably noticed from the screenshots that our buttons are now not solid colors, but gradients. And in general, gradients are a very common thing in the new design. This isn't just changing colors anymore.
In Compose, there are two main entities describing how to do any kind of fill - Color and Brush. The first is when you need to paint something in one color, the second is for any other case, particularly for gradients.
And if you somehow thought you could just tell Material components that they should now be filled with a gradient - that's not the case. The only place where you can painlessly replace Color with Brush is Modifier.background() or other similar functions from foundation. They almost always have a version for both. But any stuff from Material like Button, Surface, CircularProgressIndicator, Switch and others always only have Color in their parameters.
What to do? First, to unify the use of both, we decided to create some fill wrapper, something like this:
sealed interface Fill {
data class Solid(val color: Color) : Fill
data class Gradient(val brush: Brush) : Fill
}
// Usage example
fun Modifier.background(
fill: Fill,
shape: Shape = RectangleShape,
): Modifier = when (fill) {
is Fill.Solid -> background(fill.color, shape)
is Fill.Gradient -> background(fill.brush, shape)
}
In our components, we now always pass it, not Color, as it was before. We changed the parameters, but what to do inside the components?
Rewrite them, what else. In practice, for Compose this means we extract the guts of components to ourselves, until somewhere a bare Modifier appears or something that can take both Color and Brush.
For example, we don't use material.Button inside our component, but extract Surface from it for the click, and in it we make a Box with an overridden background. Or we go to extract the internals of CircularProgressIndicator down to drawArc, because it can have Brush set, unlike all parent functions. Each component has something of its own under the hood, but the idea is almost always the same.
The "fills" themselves can be perceived as new design system tokens and dynamically reassembled. Depending on the same brand, they can be a yellow solid or a purple-blue gradient, and this will no longer require touching the component parameters themselves.
Again, I want to complain about Google for having crappy material on top of a cool foundation. It's almost impossible to write an app without it, but it's hard to customize. We need something flexible in between foundation and material. And don't forget to make such a wrapper, please.