Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ [ShareableCardContent] Display a shadow instead of a border around the profile picture. #906

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a6da413
:wastebasket: The process of displaying the border has been removed.
Corvus400 Aug 31, 2024
c0b750e
:recycle: We have implemented a process to ensure that the profile ca…
Corvus400 Aug 31, 2024
54230f9
:wrench: ./gradlew detekt --auto-correct
Corvus400 Aug 31, 2024
34f00d1
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 1, 2024
a3e7f02
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 3, 2024
8bd53f5
Merge branch 'main' of github.com:Corvus400/conference-app-2024 into …
Corvus400 Sep 4, 2024
a386dc2
:wrench: ./gradlew detekt --auto-correct
Corvus400 Sep 4, 2024
88c9986
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 5, 2024
588db37
:wrench: The processing has been simplified.
Corvus400 Sep 5, 2024
d0f8deb
:wrench: ./gradlew detekt --auto-correct
Corvus400 Sep 5, 2024
0b1da73
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 6, 2024
519a2bb
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 6, 2024
6006238
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 6, 2024
081f99e
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 6, 2024
5b2824d
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 7, 2024
6867e80
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 7, 2024
8b16b8e
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 7, 2024
e7bce0f
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 7, 2024
7246053
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 7, 2024
ddd697d
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 7, 2024
5690ecd
Merge branch 'main' into design/display_a_shadow_instead_of_a_line
Corvus400 Sep 8, 2024
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
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package io.github.droidkaigi.confsched.profilecard.component

import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
Expand All @@ -12,7 +10,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.layer.GraphicsLayer
Expand Down Expand Up @@ -63,11 +60,6 @@ internal fun BackgroundCapturableCardBack(
qrCodeImagePainter,
modifier = Modifier
.size(width = 300.dp, height = 380.dp)
.border(
3.dp,
Color.Black,
RoundedCornerShape(8.dp),
)
.graphicsLayer {
rotationY = 180f
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package io.github.droidkaigi.confsched.profilecard.component

import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
Expand All @@ -12,7 +10,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.layer.drawLayer
import androidx.compose.ui.graphics.rememberGraphicsLayer
Expand Down Expand Up @@ -59,13 +56,7 @@ internal fun BackgroundCapturableCardFront(
FlipCardFront(
uiState,
profileImagePainter,
modifier = Modifier
.size(width = 300.dp, height = 380.dp)
.border(
3.dp,
Color.Black,
RoundedCornerShape(8.dp),
),
modifier = Modifier.size(width = 300.dp, height = 380.dp),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.layer.GraphicsLayer
import androidx.compose.ui.graphics.layer.drawLayer
import androidx.compose.ui.platform.LocalDensity
Expand Down Expand Up @@ -109,42 +113,104 @@ private fun ShareableCardContent(
.background(LocalProfileCardTheme.current.primaryColor),
) {
Box(modifier = Modifier.padding(vertical = 30.dp)) {
backImage?.let {
Image(
bitmap = it,
contentDescription = null,
modifier = Modifier
.offset(
x = with(density) { offsetXBackPx.toDp() },
y = with(density) { offsetYBackPx.toDp() },
)
.rotate(10f)
.size(
width = with(density) { cardWidthPx.toDp() },
height = with(density) { cardHeightPx.toDp() },
),
backImage?.let { backBitmap ->
ShadowedImage(
imageBitmap = backBitmap,
offsetX = offsetXBackPx,
offsetY = offsetYBackPx,
rotation = 10f,
cardWidthPx = cardWidthPx,
cardHeightPx = cardHeightPx,
)
}
frontImage?.let {
Image(
bitmap = it,
contentDescription = null,
modifier = Modifier
.offset(
x = with(density) { offsetXFrontPx.toDp() },
y = with(density) { offsetYFrontPx.toDp() },
)
.rotate(-12.2f)
.size(
width = with(density) { cardWidthPx.toDp() },
height = with(density) { cardHeightPx.toDp() },
),
frontImage?.let { frontBitmap ->
ShadowedImage(
imageBitmap = frontBitmap,
offsetX = offsetXFrontPx,
offsetY = offsetYFrontPx,
rotation = -12.2f,
cardWidthPx = cardWidthPx,
cardHeightPx = cardHeightPx,
)
}
}
}
}

@Composable
private fun ShadowedImage(
imageBitmap: ImageBitmap,
offsetX: Float,
offsetY: Float,
rotation: Float,
cardWidthPx: Int,
cardHeightPx: Int,
modifier: Modifier = Modifier,
) {
val density = LocalDensity.current
Box(
modifier = modifier
.offset(
x = with(density) { offsetX.toDp() },
y = with(density) { offsetY.toDp() },
)
.rotate(rotation)
.size(
width = with(density) { cardWidthPx.toDp() },
height = with(density) { cardHeightPx.toDp() },
)
.drawWithContent {
// Draw the blurred shadow behind the actual content.
// This function first draws a shadow by calling drawBlurredShadow(),
// then draws the actual content (the image) with drawContent().
// By doing this, we ensure the shadow appears behind the image,
// creating a layered effect with the shadow in the background.
drawBlurredShadow(size, Color.Black.copy(alpha = 0.2f))
// The child element Image is drawn by calling drawContent.
drawContent()
},
) {
Image(
bitmap = imageBitmap,
contentDescription = null,
modifier = Modifier.graphicsLayer(),
)
}
}

/**
* Draws a blurred shadow effect on the canvas.
*
* This function creates a blurred shadow by drawing multiple layers of rectangles with varying offsets
* and transparency. The shadow effect is created by gradually increasing the offset and reducing the
* opacity of each rectangle, simulating the natural fading of a shadow.
*
* @param size The size of the base rectangle to draw the shadow around.
* @param color The base color of the shadow. The alpha channel will be adjusted for the blur effect.
*/
private fun ContentDrawScope.drawBlurredShadow(size: Size, color: Color) {
// The number of shadow layers determines the smoothness of the shadow.
// Fewer layers result in a less smooth shadow.
val shadowLayers = 30

// Controls how much the shadow spreads out.
// A larger number results in a more diffused and smoother shadow.
val maxOffset = 20f

for (i in 1..shadowLayers) {
Copy link
Member

@takahirom takahirom Sep 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be difficult but, how about using Brush as the card surface effect?
https://developer.android.com/develop/ui/compose/graphics/draw/brush

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@takahirom
I tried it for a few hours, but unfortunately I couldn't get the same expression as the current implementation. 🥺

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this you might tried but how about just using .shadow(elevation= )?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@takahirom
Unfortunately, that method didn't work either. 😞
Incidentally, I tried various things afterwards, such as surrounding it with a card to see if the elevation would be displayed, but the elevation is ignored in the same way as the shadow. 💀

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@takahirom
Thank you for waiting. 🙇
I tried using the Brush method.
I think it's simpler and easier to understand than the original processing, but what do you think?
It's a little different from the original design... but if you don't want to make it too complicated, I think this is a good compromise. 🙏

val offset = i * (maxOffset / shadowLayers)
drawRect(
// The shadow is darkest at its base, and becomes lighter as it extends further away.
color = color.copy(alpha = 0.05f / i),
// The shadow extends diagonally from the upper left to the lower right.
topLeft = Offset(offset, offset),
// Increasing the size of the rectangles with each iteration creates the effect of a shadow
// that gets thinner and more diffused the further it is from the base.
size = Size(size.width + offset, size.height + offset),
)
}
}

@Composable
@Preview
fun ShareableCardPreview() {
Expand Down
Loading