android: fix issue where default avatar wasn't shown (#558)

Always render the default icon first so that if the profile picture is not loaded or has an issue, the default is shown.

Fixes tailscale/corp#24217

Signed-off-by: kari-ts <kari@tailscale.com>
kari/test
kari-ts 1 year ago committed by GitHub
parent 18ca09d0f3
commit 4c4148bd8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -43,43 +43,53 @@ fun Avatar(
var isFocused = remember { mutableStateOf(false) } var isFocused = remember { mutableStateOf(false) }
val focusManager = LocalFocusManager.current val focusManager = LocalFocusManager.current
// Determine the modifier based on whether the avatar is focusable // Outer Box for the larger focusable and clickable area
val outerModifier = Box(
Modifier.then( contentAlignment = Alignment.Center,
if (isFocusable) { modifier = Modifier
Modifier.padding(4.dp) .padding(4.dp)
} else Modifier) // Add padding if focusable .size((size * 1.5f).dp) // Focusable area is larger than the avatar
.size((size * 1.5f).dp) .clip(CircleShape) // Ensure both the focus and click area are circular
.clip(CircleShape) .background(
.background(if (isFocused.value) MaterialTheme.colorScheme.surface else Color.Transparent) if (isFocused.value) MaterialTheme.colorScheme.surface
.onFocusChanged { focusState -> isFocused.value = focusState.isFocused } else Color.Transparent,
.then(if (isFocusable) Modifier.focusable() else Modifier) // Conditionally add focusable )
.clickable( .onFocusChanged { focusState ->
interactionSource = remember { MutableInteractionSource() }, isFocused.value = focusState.isFocused
indication = ripple(bounded = true), }
onClick = { .focusable() // Make this outer Box focusable (after onFocusChanged)
action?.invoke() .clickable(
focusManager.clearFocus() // Clear focus after clicking interactionSource = remember { MutableInteractionSource() },
}) indication = ripple(bounded = true), // Apply ripple effect inside circular bounds
onClick = {
// Outer Box for the larger focusable and clickable area action?.invoke()
Box(contentAlignment = Alignment.Center, modifier = outerModifier) { focusManager.clearFocus() // Clear focus after clicking the avatar
// Inner Box to hold the avatar content (Icon or AsyncImage) }
Box(contentAlignment = Alignment.Center, modifier = Modifier.size(size.dp).clip(CircleShape)) {
if (profile?.UserProfile?.ProfilePicURL != null) {
AsyncImage(
model = profile.UserProfile.ProfilePicURL,
modifier = Modifier.size(size.dp).clip(CircleShape),
contentDescription = null)
} else {
Icon(
imageVector = Icons.Default.Person,
contentDescription = stringResource(R.string.settings_title),
modifier =
Modifier.size((size * 0.8f).dp)
.clip(CircleShape) // Icon size slightly smaller than the Box
) )
} ) {
} // Inner Box to hold the avatar content (Icon or AsyncImage)
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(size.dp)
.clip(CircleShape)
) {
// Always display the default icon as a background layer
Icon(
imageVector = Icons.Default.Person,
contentDescription = stringResource(R.string.settings_title),
modifier =
Modifier.size((size * 0.8f).dp)
.clip(CircleShape) // Icon size slightly smaller than the Box
)
// Overlay the profile picture if available
profile?.UserProfile?.ProfilePicURL?.let { url ->
AsyncImage(
model = url,
modifier = Modifier.size(size.dp).clip(CircleShape),
contentDescription = null)
}
}
} }
} }

Loading…
Cancel
Save