Skip to content

Commit c6ff4a1

Browse files
authored
Add skeleton loader for Followed by section on profile details (#1088)
1 parent 2065dc7 commit c6ff4a1

1 file changed

Lines changed: 52 additions & 7 deletions

File tree

app/src/main/kotlin/net/primal/android/profile/details/ui/ProfileDetailsHeader.kt

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@ import androidx.compose.animation.fadeIn
66
import androidx.compose.animation.fadeOut
77
import androidx.compose.animation.shrinkVertically
88
import androidx.compose.foundation.background
9+
import androidx.compose.foundation.border
910
import androidx.compose.foundation.clickable
1011
import androidx.compose.foundation.layout.Arrangement
1112
import androidx.compose.foundation.layout.Box
1213
import androidx.compose.foundation.layout.Column
1314
import androidx.compose.foundation.layout.Row
14-
import androidx.compose.foundation.layout.Spacer
1515
import androidx.compose.foundation.layout.fillMaxWidth
1616
import androidx.compose.foundation.layout.height
1717
import androidx.compose.foundation.layout.padding
18+
import androidx.compose.foundation.layout.size
19+
import androidx.compose.foundation.shape.CircleShape
1820
import androidx.compose.material3.ExperimentalMaterial3Api
1921
import androidx.compose.material3.SnackbarDuration
2022
import androidx.compose.material3.SnackbarHostState
@@ -54,6 +56,7 @@ import net.primal.android.core.compose.AvatarOverlap
5456
import net.primal.android.core.compose.AvatarThumbnailsRow
5557
import net.primal.android.core.compose.IconText
5658
import net.primal.android.core.compose.NostrUserText
59+
import net.primal.android.core.compose.PulsingListItemPlaceholder
5760
import net.primal.android.core.compose.preview.PrimalPreview
5861
import net.primal.android.core.compose.profile.model.ProfileDetailsUi
5962
import net.primal.android.core.compose.profile.model.ProfileStatsUi
@@ -259,11 +262,8 @@ private fun ProfileHeaderDetails(
259262
onProfileClick = onProfileClick,
260263
)
261264
} else {
262-
Spacer(
263-
modifier = Modifier
264-
.padding(vertical = 8.dp)
265-
.fillMaxWidth()
266-
.height(36.dp),
265+
UserFollowedByIndicatorPlaceholder(
266+
modifier = Modifier.padding(horizontal = 14.dp, vertical = 8.dp),
267267
)
268268
}
269269
}
@@ -291,7 +291,7 @@ private fun UserFollowedByIndicator(
291291
avatarOverlap = AvatarOverlap.Start,
292292
avatarBorderSize = 1.dp,
293293
avatarSize = 36.dp,
294-
maxAvatarsToShow = 5,
294+
maxAvatarsToShow = FOLLOWED_BY_AVATAR_COUNT,
295295
displayAvatarOverflowIndicator = false,
296296
)
297297
val text =
@@ -306,6 +306,51 @@ private fun UserFollowedByIndicator(
306306
}
307307
}
308308

309+
@Composable
310+
private fun UserFollowedByIndicatorPlaceholder(modifier: Modifier = Modifier) {
311+
Row(
312+
horizontalArrangement = Arrangement.spacedBy(8.dp),
313+
verticalAlignment = Alignment.CenterVertically,
314+
modifier = modifier,
315+
) {
316+
val avatarSize = 36.dp
317+
val avatarSpacing = avatarSize * (1f - FOLLOWED_BY_AVATAR_OVERLAP)
318+
Box(
319+
modifier = Modifier.size(
320+
width = avatarSpacing * (FOLLOWED_BY_AVATAR_COUNT - 1) + avatarSize,
321+
height = avatarSize,
322+
),
323+
) {
324+
for (index in FOLLOWED_BY_AVATAR_COUNT - 1 downTo 0) {
325+
Box(
326+
modifier = Modifier
327+
.padding(start = avatarSpacing * index)
328+
.size(avatarSize)
329+
.border(
330+
width = 1.dp,
331+
color = AppTheme.colorScheme.background,
332+
shape = CircleShape,
333+
),
334+
) {
335+
PulsingListItemPlaceholder(
336+
height = avatarSize,
337+
width = avatarSize,
338+
shape = CircleShape,
339+
)
340+
}
341+
}
342+
}
343+
PulsingListItemPlaceholder(
344+
modifier = Modifier.weight(1f),
345+
height = 32.dp,
346+
shape = AppTheme.shapes.small,
347+
)
348+
}
349+
}
350+
351+
private const val FOLLOWED_BY_AVATAR_COUNT = 5
352+
private const val FOLLOWED_BY_AVATAR_OVERLAP = 0.25f
353+
309354
@Composable
310355
private fun ProfileFollowIndicators(
311356
modifier: Modifier = Modifier,

0 commit comments

Comments
 (0)