@@ -29,6 +29,7 @@ import androidx.compose.ui.res.stringResource
2929import androidx.compose.ui.unit.dp
3030import coil.annotation.ExperimentalCoilApi
3131import coil.compose.AsyncImage
32+ import coil.compose.AsyncImagePainter
3233import com.tailscale.ipn.R
3334import com.tailscale.ipn.ui.model.IpnLocal
3435import com.tailscale.ipn.ui.util.AndroidTVUtil
@@ -44,6 +45,7 @@ fun Avatar(
4445) {
4546 val isFocused = remember { mutableStateOf(false ) }
4647 val focusManager = LocalFocusManager .current
48+ val isIconLoaded = remember { mutableStateOf(false ) }
4749
4850 // Outer Box for the larger focusable and clickable area
4951 Box (
@@ -73,20 +75,28 @@ fun Avatar(
7375 contentAlignment = Alignment .Center ,
7476 modifier = Modifier .size(size.dp).clip(CircleShape )) {
7577 // Always display the default icon as a background layer
76- Icon (
77- imageVector = Icons .Default .Person ,
78- contentDescription = stringResource(R .string.settings_title),
79- modifier =
80- Modifier .conditional(AndroidTVUtil .isAndroidTV(), { size((size * 0.8f ).dp) })
81- .clip(CircleShape ) // Icon size slightly smaller than the Box
82- )
78+ if (! isIconLoaded.value) {
79+ Icon (
80+ imageVector = Icons .Default .Person ,
81+ contentDescription = stringResource(R .string.settings_title),
82+ modifier =
83+ Modifier .conditional(
84+ AndroidTVUtil .isAndroidTV(), { size((size * 0.8f ).dp) })
85+ .clip(CircleShape ) // Icon size slightly smaller than the Box
86+ )
87+ }
8388
8489 // Overlay the profile picture if available
8590 profile?.UserProfile ?.ProfilePicURL ?.let { url ->
8691 AsyncImage (
8792 model = url,
8893 modifier = Modifier .size(size.dp).clip(CircleShape ),
89- contentDescription = null )
94+ contentDescription = null ,
95+ onState = { state ->
96+ if (state is AsyncImagePainter .State .Success ) {
97+ isIconLoaded.value = true
98+ }
99+ })
90100 }
91101 }
92102 }
0 commit comments