-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add common
ProfileImage
composable (#585)
* Add Coil Compose + Zoomable dependencies * Add content description string
- Loading branch information
1 parent
3aa212d
commit 148ffbb
Showing
5 changed files
with
183 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
core/auth/ui/compose/src/main/kotlin/com/edricchan/studybuddy/core/auth/ui/Profile.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package com.edricchan.studybuddy.core.auth.ui | ||
|
||
import android.content.Context | ||
import android.net.Uri | ||
import androidx.compose.foundation.shape.CircleShape | ||
import androidx.compose.material.icons.Icons | ||
import androidx.compose.material.icons.outlined.AccountCircle | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.draw.clip | ||
import androidx.compose.ui.graphics.Shape | ||
import androidx.compose.ui.graphics.vector.rememberVectorPainter | ||
import androidx.compose.ui.layout.ContentScale | ||
import androidx.compose.ui.platform.LocalContext | ||
import androidx.compose.ui.res.stringResource | ||
import androidx.core.net.toUri | ||
import coil.compose.AsyncImage | ||
import coil.request.ImageRequest | ||
import com.edricchan.studybuddy.core.auth.common.R | ||
import com.edricchan.studybuddy.core.auth.ui.painter.tintedPainter | ||
import com.edricchan.studybuddy.exts.coil.imageRequest | ||
import me.saket.telephoto.zoomable.coil.ZoomableAsyncImage | ||
|
||
/** | ||
* Displays a user's profile picture given the [photoUrl]. | ||
* The image is [cropped][Modifier.clip] with the specified [shape]. | ||
* @param modifier Modifier to be passed to [AsyncImage]. | ||
* @param shape The [Shape] to [crop][Modifier.clip] the contents to. | ||
* @param displayName The user's display name. | ||
* @param photoUrl URL to the profile picture as a [String]. | ||
* @param context Context to be used to create an [ImageRequest]. | ||
* @param isZoomable Whether the image should be [zoomable][ZoomableAsyncImage]. | ||
* @param imageRequestInit Additional configuration to be passed to the [ImageRequest.Builder]. | ||
*/ | ||
@Composable | ||
fun ProfileImage( | ||
modifier: Modifier = Modifier, | ||
shape: Shape = CircleShape, | ||
displayName: String, | ||
photoUrl: String?, | ||
context: Context = LocalContext.current, | ||
isZoomable: Boolean = false, | ||
imageRequestInit: ImageRequest.Builder.() -> Unit = {} | ||
) = ProfileImage( | ||
modifier = modifier, | ||
shape = shape, | ||
displayName = displayName, | ||
photoUri = photoUrl?.toUri(), | ||
context = context, | ||
isZoomable = isZoomable, | ||
imageRequestInit = imageRequestInit | ||
) | ||
|
||
/** | ||
* Displays a user's profile picture given the [photoUri]. | ||
* The image is [cropped][Modifier.clip] with the specified [shape]. | ||
* @param modifier Modifier to be passed to [AsyncImage]. | ||
* @param shape The [Shape] to [crop][Modifier.clip] the contents to. | ||
* @param displayName The user's display name. | ||
* @param photoUri URL to the profile picture as a [Uri]. | ||
* @param context Context to be used to create an [ImageRequest]. | ||
* @param isZoomable Whether the image should be [zoomable][ZoomableAsyncImage]. | ||
* @param imageRequestInit Additional configuration to be passed to the [ImageRequest.Builder]. | ||
*/ | ||
@Composable | ||
fun ProfileImage( | ||
modifier: Modifier = Modifier, | ||
shape: Shape = CircleShape, | ||
displayName: String, | ||
photoUri: Uri?, | ||
context: Context = LocalContext.current, | ||
isZoomable: Boolean = false, | ||
imageRequestInit: ImageRequest.Builder.() -> Unit = {} | ||
) { | ||
val model = context.imageRequest { | ||
data(photoUri) | ||
crossfade(true) | ||
imageRequestInit() | ||
} | ||
if (isZoomable) { | ||
ZoomableAsyncImage( | ||
model = model, | ||
contentDescription = stringResource(R.string.account_profile_content_desc, displayName), | ||
contentScale = ContentScale.Crop, | ||
modifier = modifier | ||
) | ||
} else { | ||
AsyncImage( | ||
modifier = modifier.clip(shape), | ||
model = model, | ||
placeholder = tintedPainter(rememberVectorPainter(Icons.Outlined.AccountCircle)), | ||
contentDescription = stringResource(R.string.account_profile_content_desc, displayName), | ||
contentScale = ContentScale.Crop, | ||
) | ||
} | ||
} |
75 changes: 75 additions & 0 deletions
75
...ompose/src/main/kotlin/com/edricchan/studybuddy/core/auth/ui/painter/ForwardingPainter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// From https://gist.github.com/colinrtwhite/c2966e0b8584b4cdf0a5b05786b20ae1 | ||
package com.edricchan.studybuddy.core.auth.ui.painter | ||
|
||
import androidx.compose.material3.LocalContentColor | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.graphics.Color | ||
import androidx.compose.ui.graphics.ColorFilter | ||
import androidx.compose.ui.graphics.DefaultAlpha | ||
import androidx.compose.ui.graphics.drawscope.DrawScope | ||
import androidx.compose.ui.graphics.painter.Painter | ||
|
||
/** | ||
* Create and return a new [Painter] that wraps [painter] with its [alpha], [colorFilter], or [onDraw] overwritten. | ||
*/ | ||
internal fun forwardingPainter( | ||
painter: Painter, | ||
alpha: Float = DefaultAlpha, | ||
colorFilter: ColorFilter? = null, | ||
onDraw: DrawScope.(ForwardingDrawInfo) -> Unit = DefaultOnDraw, | ||
): Painter = ForwardingPainter(painter, alpha, colorFilter, onDraw) | ||
|
||
/** | ||
* Variant of [forwardingPainter] which tints the [painter] with the given [tint] colour. | ||
* @see forwardingPainter | ||
*/ | ||
@Composable | ||
internal fun tintedPainter( | ||
painter: Painter, | ||
alpha: Float = DefaultAlpha, | ||
tint: Color = LocalContentColor.current | ||
): Painter = forwardingPainter(painter, alpha, colorFilter = ColorFilter.tint(tint)) | ||
|
||
internal data class ForwardingDrawInfo( | ||
val painter: Painter, | ||
val alpha: Float, | ||
val colorFilter: ColorFilter?, | ||
) | ||
|
||
private class ForwardingPainter( | ||
private val painter: Painter, | ||
private var alpha: Float, | ||
private var colorFilter: ColorFilter?, | ||
private val onDraw: DrawScope.(ForwardingDrawInfo) -> Unit, | ||
) : Painter() { | ||
|
||
private var info = newInfo() | ||
|
||
override val intrinsicSize get() = painter.intrinsicSize | ||
|
||
override fun applyAlpha(alpha: Float): Boolean { | ||
if (alpha != DefaultAlpha) { | ||
this.alpha = alpha | ||
this.info = newInfo() | ||
} | ||
return true | ||
} | ||
|
||
override fun applyColorFilter(colorFilter: ColorFilter?): Boolean { | ||
if (colorFilter != null) { | ||
this.colorFilter = colorFilter | ||
this.info = newInfo() | ||
} | ||
return true | ||
} | ||
|
||
override fun DrawScope.onDraw() = onDraw(info) | ||
|
||
private fun newInfo() = ForwardingDrawInfo(painter, alpha, colorFilter) | ||
} | ||
|
||
private val DefaultOnDraw: DrawScope.(ForwardingDrawInfo) -> Unit = { info -> | ||
with(info.painter) { | ||
draw(size, info.alpha, info.colorFilter) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters