From 8997cd2ba2315c94035568f5058d98b830c898c3 Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Thu, 23 Apr 2026 16:51:15 +0200 Subject: [PATCH] Render profile list item. --- .../compose/database/model/Profile.kt | 89 +++++++++++++++++++ .../widgets/detail/MetadataEventDetail.kt | 12 +-- .../widgets/profile/ProfileAvatar.kt | 11 ++- .../ui/view/model/FollowersListViewModel.kt | 22 +---- .../ui/view/model/FollowingListViewModel.kt | 22 +---- 5 files changed, 109 insertions(+), 47 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/Profile.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/Profile.kt index d8ab4fc7..aa1d246d 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/Profile.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/Profile.kt @@ -6,6 +6,25 @@ import ac.cord.auxiliary.compose.database.model.traits.NostrEventEntity import ac.cord.auxiliary.compose.database.model.traits.SoftDeletableEntity import ac.cord.auxiliary.compose.database.model.traits.TimestampedEntity import ac.cord.auxiliary.compose.database.model.traits.UserViewableEntity +import ac.cord.auxiliary.compose.ui.composable.navigation.routes.NostrEventDetailRoute +import ac.cord.auxiliary.compose.ui.composable.navigation.routes.Route +import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileAvatar +import ac.cord.auxiliary.compose.ui.theme.AuxTheme +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Card +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.Index @@ -56,4 +75,74 @@ data class Profile( fun humanReadableNameOrPubkey(): String { return displayName ?: userName ?: nip05 ?: twitter ?: publicKey } + + @Composable + fun RenderAsListItem( + onNavigateToEvent: (Route) -> Unit + ) { + Card( + modifier = Modifier.fillMaxWidth().padding( + horizontal = 6.dp, + vertical = 3.dp + ), + onClick = { + onNavigateToEvent.invoke( + NostrEventDetailRoute( + nostrEventId + ) + ) + } + ) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy( + space = 4.dp, + alignment = Alignment.Start + ) + ) { + Column { + ProfileAvatar( + publicKey = publicKey, + profile = this@Profile + ) + } + + Column( + modifier = Modifier.weight(1f) + ) { + Text( + text = humanReadableNameOrPubkey(), + style = MaterialTheme.typography.bodyMedium + ) + + Text( + text = nip05 ?: "", + style = MaterialTheme.typography.labelMedium + ) + } + } + } + } +} + +@Preview +@Composable +fun ProfileRenderAsListItemPreview() { + val profile = Profile( + publicKey = "pubKey", + displayName = "John Doe", + nip05 = "john@doe.com", + about = "I am the stone that the builder refused.", + nostrEventId = "nostrEventId" + ) + AuxTheme { + Surface( + modifier = Modifier.padding(20.dp) + ) { + profile.RenderAsListItem( + onNavigateToEvent = {} + ) + } + } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/widgets/detail/MetadataEventDetail.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/widgets/detail/MetadataEventDetail.kt index 08a68923..575c7c93 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/widgets/detail/MetadataEventDetail.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/widgets/detail/MetadataEventDetail.kt @@ -5,6 +5,7 @@ import ac.cord.auxiliary.compose.database.model.Profile import ac.cord.auxiliary.compose.database.model.intermdiate.LocalNostrEvent import ac.cord.auxiliary.compose.repository.NostrRepository import ac.cord.auxiliary.compose.ui.composable.navigation.routes.Route +import ac.cord.auxiliary.compose.ui.composable.widgets.profile.ProfileAvatar import ac.cord.auxiliary.compose.ui.theme.AuxTheme import ac.cord.auxiliary.compose.ui.view.model.FeedListViewModel import ac.cord.auxiliary.compose.ui.view.model.FollowersListViewModel @@ -25,6 +26,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBackIosNew import androidx.compose.material.icons.filled.Bolt @@ -48,6 +50,7 @@ import androidx.compose.runtime.key import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow @@ -145,11 +148,10 @@ fun MetadataEventDetail( horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically ) { - - Icon( - Icons.Default.Person, - modifier = Modifier.size(50.dp), - contentDescription = profile?.displayName ?: profile?.userName ?: "Profile picture" + ProfileAvatar( + modifier = Modifier.size(75.dp).clip(shape = CircleShape), + profile = profile, + publicKey = localNostrEvent.nostrEvent.pubKey ) diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/widgets/profile/ProfileAvatar.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/widgets/profile/ProfileAvatar.kt index a7150a8c..9ea507de 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/widgets/profile/ProfileAvatar.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/widgets/profile/ProfileAvatar.kt @@ -25,7 +25,11 @@ import coil3.compose.AsyncImage import kotlin.math.abs @Composable -fun ProfileAvatar(publicKey: String, profile: Profile?) { +fun ProfileAvatar( + modifier: Modifier = Modifier.size(55.dp).clip(shape = CircleShape), + publicKey: String, + profile: Profile? +) { val tintColor = Color.hsl( hue = abs( publicKey.hashCode() @@ -33,11 +37,10 @@ fun ProfileAvatar(publicKey: String, profile: Profile?) { saturation = 0.55f, lightness = 0.45f ) - val imageModifier = Modifier.size(55.dp).clip(shape = CircleShape) if (profile?.picture == null) { Icon( - modifier = imageModifier, + modifier = modifier, imageVector = Icons.Default.AccountCircle, tint = tintColor, contentDescription = "Profile picture", @@ -60,7 +63,7 @@ fun ProfileAvatar(publicKey: String, profile: Profile?) { AsyncImage( model = profile.picture, - modifier = imageModifier, + modifier = modifier, contentDescription = "Profile picture for ${profile.displayName ?: profile.publicKey}", placeholder = placeHolderGraphic, fallback = fallbackGraphic, diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowersListViewModel.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowersListViewModel.kt index 643b3e03..478d69aa 100755 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowersListViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowersListViewModel.kt @@ -144,25 +144,9 @@ class FollowersListViewModel( items = followersListUIState.followers, key = { profile -> profile.publicKey } ) { follower -> - Column( - modifier = Modifier.clickable { - onNavigateToEvent.invoke( - NostrEventDetailRoute( - follower.nostrEventId - ) - ) - } - ) { - Text( - text = follower.displayName ?: follower.userName ?: follower.userName ?: follower.publicKey - ) - - follower.nip05?.let { - Text( - text = follower.nip05 - ) - } - } + follower.RenderAsListItem( + onNavigateToEvent = onNavigateToEvent + ) } } } diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowingListViewModel.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowingListViewModel.kt index ed3c08aa..e03af8cb 100755 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowingListViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/FollowingListViewModel.kt @@ -143,25 +143,9 @@ class FollowingListViewModel( items = feedListUIState.following, key = { profile -> profile.publicKey } ) { profile -> - Column( - modifier = Modifier.clickable { - onNavigateToEvent.invoke( - NostrEventDetailRoute( - profile.nostrEventId - ) - ) - } - ) { - Text( - text = profile.displayName ?: profile.userName ?: profile.userName ?: profile.publicKey - ) - - profile.nip05?.let { - Text( - text = profile.nip05 - ) - } - } + profile.RenderAsListItem( + onNavigateToEvent = onNavigateToEvent + ) } } }