Add workaround for blur in ElementLogoAtom for OS < 9. (#1061)
* Add workaround for blur in `ElementLogoAtom` for OS < 9. * Update screenshots * Pass `useBlurredShadow` to `ElementLogoAtom` * Update screenshots --------- Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
parent
8a62abe93e
commit
75c19a7e04
16 changed files with 178 additions and 84 deletions
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package io.element.android.libraries.designsystem.atomic.atoms
|
||||
|
||||
import android.graphics.BlurMaskFilter
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
|
|
@ -27,24 +26,16 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.blur
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.CornerRadius
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.geometry.RoundRect
|
||||
import androidx.compose.ui.graphics.ClipOp
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Paint
|
||||
import androidx.compose.ui.graphics.Path
|
||||
import androidx.compose.ui.graphics.drawscope.clipPath
|
||||
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.R
|
||||
import io.element.android.libraries.designsystem.modifiers.blurCompat
|
||||
import io.element.android.libraries.designsystem.modifiers.blurredShapeShadow
|
||||
import io.element.android.libraries.designsystem.modifiers.canUseBlurMaskFilter
|
||||
import io.element.android.libraries.designsystem.preview.DayNightPreviews
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.theme.ElementTheme
|
||||
|
|
@ -53,6 +44,7 @@ import io.element.android.libraries.theme.ElementTheme
|
|||
fun ElementLogoAtom(
|
||||
size: ElementLogoAtomSize,
|
||||
modifier: Modifier = Modifier,
|
||||
useBlurredShadow: Boolean = canUseBlurMaskFilter(),
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
) {
|
||||
val blur = if (darkTheme) 160.dp else 24.dp
|
||||
|
|
@ -66,22 +58,35 @@ fun ElementLogoAtom(
|
|||
.border(size.borderWidth, borderColor, RoundedCornerShape(size.cornerRadius)),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Box(
|
||||
Modifier
|
||||
.size(size.outerSize)
|
||||
.shapeShadow(
|
||||
color = shadowColor,
|
||||
cornerRadius = size.cornerRadius,
|
||||
blurRadius = size.shadowRadius,
|
||||
offsetY = 8.dp,
|
||||
)
|
||||
)
|
||||
if (useBlurredShadow) {
|
||||
Box(
|
||||
Modifier
|
||||
.size(size.outerSize)
|
||||
.blurredShapeShadow(
|
||||
color = shadowColor,
|
||||
cornerRadius = size.cornerRadius,
|
||||
blurRadius = size.shadowRadius,
|
||||
offsetY = 8.dp,
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Box(
|
||||
Modifier
|
||||
.size(size.outerSize)
|
||||
.shadow(
|
||||
elevation = size.shadowRadius,
|
||||
shape = RoundedCornerShape(size.cornerRadius),
|
||||
clip = false,
|
||||
ambientColor = shadowColor
|
||||
)
|
||||
)
|
||||
}
|
||||
Box(
|
||||
Modifier
|
||||
.clip(RoundedCornerShape(size.cornerRadius))
|
||||
.size(size.outerSize)
|
||||
.background(backgroundColor)
|
||||
.blur(blur)
|
||||
.blurCompat(blur)
|
||||
)
|
||||
Image(
|
||||
modifier = Modifier.size(size.logoSize),
|
||||
|
|
@ -121,44 +126,6 @@ sealed class ElementLogoAtomSize(
|
|||
)
|
||||
}
|
||||
|
||||
fun Modifier.shapeShadow(
|
||||
color: Color = Color.Black,
|
||||
cornerRadius: Dp = 0.dp,
|
||||
offsetX: Dp = 0.dp,
|
||||
offsetY: Dp = 0.dp,
|
||||
blurRadius: Dp = 0.dp,
|
||||
) = then(
|
||||
drawBehind {
|
||||
drawIntoCanvas { canvas ->
|
||||
val path = Path().apply {
|
||||
addRoundRect(RoundRect(Rect(Offset.Zero, size), CornerRadius(cornerRadius.toPx())))
|
||||
}
|
||||
|
||||
clipPath(path, ClipOp.Difference) {
|
||||
val paint = Paint()
|
||||
val frameworkPaint = paint.asFrameworkPaint()
|
||||
if (blurRadius != 0.dp) {
|
||||
frameworkPaint.maskFilter = BlurMaskFilter(blurRadius.toPx(), BlurMaskFilter.Blur.NORMAL)
|
||||
}
|
||||
frameworkPaint.color = color.toArgb()
|
||||
|
||||
val leftPixel = offsetX.toPx()
|
||||
val topPixel = offsetY.toPx()
|
||||
val rightPixel = size.width + topPixel
|
||||
val bottomPixel = size.height + leftPixel
|
||||
|
||||
canvas.drawRect(
|
||||
left = leftPixel,
|
||||
top = topPixel,
|
||||
right = rightPixel,
|
||||
bottom = bottomPixel,
|
||||
paint = paint,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@Composable
|
||||
@DayNightPreviews
|
||||
internal fun ElementLogoAtomMediumPreview() {
|
||||
|
|
@ -172,7 +139,19 @@ internal fun ElementLogoAtomLargePreview() {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview(elementLogoAtomSize: ElementLogoAtomSize) {
|
||||
@DayNightPreviews
|
||||
internal fun ElementLogoAtomMediumNoBlurShadowPreview() {
|
||||
ContentToPreview(ElementLogoAtomSize.Medium, useBlurredShadow = false)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@DayNightPreviews
|
||||
internal fun ElementLogoAtomLargeNoBlurShadowPreview() {
|
||||
ContentToPreview(ElementLogoAtomSize.Large, useBlurredShadow = false)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview(elementLogoAtomSize: ElementLogoAtomSize, useBlurredShadow: Boolean = true) {
|
||||
ElementPreview {
|
||||
Box(
|
||||
Modifier
|
||||
|
|
@ -180,7 +159,7 @@ private fun ContentToPreview(elementLogoAtomSize: ElementLogoAtomSize) {
|
|||
.background(ElementTheme.colors.bgSubtlePrimary),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
ElementLogoAtom(elementLogoAtomSize)
|
||||
ElementLogoAtom(elementLogoAtomSize, useBlurredShadow = useBlurredShadow)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.modifiers
|
||||
|
||||
import android.graphics.BlurMaskFilter
|
||||
import android.os.Build
|
||||
import androidx.annotation.ChecksSdkIntAtLeast
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.draw.BlurredEdgeTreatment
|
||||
import androidx.compose.ui.draw.blur
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.CornerRadius
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.geometry.RoundRect
|
||||
import androidx.compose.ui.graphics.ClipOp
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Paint
|
||||
import androidx.compose.ui.graphics.Path
|
||||
import androidx.compose.ui.graphics.drawscope.clipPath
|
||||
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* @return true if the blur modifier is supported on the current OS version.
|
||||
*
|
||||
* The docs say the `blur` modifier is only supported on Android 12+:
|
||||
* https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier#(androidx.compose.ui.Modifier).blur(androidx.compose.ui.unit.Dp,androidx.compose.ui.draw.BlurredEdgeTreatment)
|
||||
* */
|
||||
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S)
|
||||
fun canUseBlur(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
||||
|
||||
@Composable
|
||||
fun canUseBlurMaskFilter() = !LocalView.current.isHardwareAccelerated
|
||||
|
||||
fun Modifier.blurredShapeShadow(
|
||||
color: Color = Color.Black,
|
||||
cornerRadius: Dp = 0.dp,
|
||||
offsetX: Dp = 0.dp,
|
||||
offsetY: Dp = 0.dp,
|
||||
blurRadius: Dp = 0.dp,
|
||||
) = then(
|
||||
drawBehind {
|
||||
drawIntoCanvas { canvas ->
|
||||
val path = Path().apply {
|
||||
addRoundRect(RoundRect(Rect(Offset.Zero, size), CornerRadius(cornerRadius.toPx())))
|
||||
}
|
||||
|
||||
// Draw the blurred shadow, then cut out the shape from it
|
||||
clipPath(path, ClipOp.Difference) {
|
||||
val paint = Paint()
|
||||
val frameworkPaint = paint.asFrameworkPaint()
|
||||
if (blurRadius != 0.dp) {
|
||||
frameworkPaint.maskFilter = BlurMaskFilter(blurRadius.toPx(), BlurMaskFilter.Blur.NORMAL)
|
||||
}
|
||||
frameworkPaint.color = color.toArgb()
|
||||
|
||||
val leftPixel = offsetX.toPx()
|
||||
val topPixel = offsetY.toPx()
|
||||
val rightPixel = size.width + topPixel
|
||||
val bottomPixel = size.height + leftPixel
|
||||
|
||||
canvas.drawRect(
|
||||
left = leftPixel,
|
||||
top = topPixel,
|
||||
right = rightPixel,
|
||||
bottom = bottomPixel,
|
||||
paint = paint,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
fun Modifier.blurCompat(
|
||||
radius: Dp,
|
||||
edgeTreatment: BlurredEdgeTreatment = BlurredEdgeTreatment.Rectangle
|
||||
): Modifier = composed {
|
||||
when {
|
||||
radius.value == 0f -> this
|
||||
canUseBlur() -> blur(radius, edgeTreatment)
|
||||
else -> this // Added in case we find a way to make this work on older devices
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6d2eab27a1132893542b240399a4003b4049b72903a822077f69dd9dafd26f71
|
||||
size 299106
|
||||
oid sha256:2cc8d498816a04c537ad2835068a2badab656aa723a900b471c8f79320d7967c
|
||||
size 300473
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fbad2f74e329a424e75ef96cb0c427a7baba044f3267346756324c39ebd6add6
|
||||
size 404196
|
||||
oid sha256:634dc94c58f6e7aed8abf9c11f33e81a65e81c439b247321a398e3728d5696d4
|
||||
size 401397
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:56f53e2c13480d5f31d38c671612c81fa802e1f35a55ada99d544917f01b91ba
|
||||
size 338952
|
||||
oid sha256:4bf8563c80e874ff79850e37bbf71609aac72c62c74cbe8255e403bd00feadc3
|
||||
size 326514
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cfe3663daab250bcd733ab746e4864472691b40cf927a3cd73d15b323dec2b68
|
||||
size 329945
|
||||
oid sha256:45984b598d30a2511e03644927a9f1f34b4173f2eebb8a328a19df8643385f18
|
||||
size 317243
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c449e6e4162f12a6be7faa668b930b294489ae217c2a7493f5671145a926079e
|
||||
size 340944
|
||||
oid sha256:1d96057db48fd7e3461fde86b84c09688c0af49e51bcd94affa2df9c9785b6f5
|
||||
size 327755
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0355120442254880360b982df6c2c7cce84a471f632436c96e79ffafed35de14
|
||||
size 324378
|
||||
oid sha256:4007453c80be5700ec9942983ef903a2404e7e3879d82c189a5e95687916e8eb
|
||||
size 310597
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5d05151967955c961ca47619de2f28f86d0350299b61fbef0371c1706439a844
|
||||
size 421908
|
||||
oid sha256:5b07c105d41caf87c34a506138ff5d43df853d9b7b7143e0099f222886ca217e
|
||||
size 420316
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3a2056882e65afe8fc2d0dc60efc7912ca5674acb57e3690136a8704f9f063ed
|
||||
size 407942
|
||||
oid sha256:738ee59035ecbc006ccd43ff10ce847d6d741da780b3e189c221b55a1b6ec06c
|
||||
size 405327
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6521d409bc1fc70fa422ffec400d9f20d0b7fe16adebb7f5b0a9e5f135328ffc
|
||||
size 422213
|
||||
oid sha256:1b3ba2db52bd7ee1713ba1b276b0e3a4a7edf406a8833027d548c9fdf4dbe838
|
||||
size 419123
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d39cfdb0db12a6d14f3105aa168ea002a845d2083f07ecfabe0858739507018d
|
||||
size 396789
|
||||
oid sha256:4bd69417650f09e240405d839464ba716d55d01e6230a9aa8b923460b4c88443
|
||||
size 393093
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3f76220968b3e28b2c1ddd91b4036bf037a98e97c859e8616314ed953862cc64
|
||||
size 42525
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3321dd27c1fbe47df862dad9b591faf9279da1ea4eb66b7b900d8c962280a74e
|
||||
size 31811
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ca4e1e3cd5d7cb9fd8416bc7074272b759bbc501993829b6edef6809cf519aee
|
||||
size 27532
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8615ceb43c29becd4cfe6062d8fc844b15b717e8f2e5d7b151bdc4478de59381
|
||||
size 20607
|
||||
Loading…
Add table
Add a link
Reference in a new issue