feat(home): partner photoUrl loaded and displayed in identity card

- PartnerHomeViewModel: loads partner photoUrl alongside name
- PartnerIdentityCard: shows AsyncImage when photoUrl available, fallback to initial letter
This commit is contained in:
null 2026-06-24 15:20:32 -05:00
parent a8fbbaa286
commit adb61715fe
1 changed files with 37 additions and 18 deletions

View File

@ -44,7 +44,10 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import coil.compose.AsyncImage
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -77,6 +80,7 @@ data class PartnerHomeUiState(
val isLoading: Boolean = true, val isLoading: Boolean = true,
val error: String? = null, val error: String? = null,
val partnerName: String? = null, val partnerName: String? = null,
val partnerPhotoUrl: String? = null,
val streakCount: Int = 0, val streakCount: Int = 0,
val hasPartnerAnsweredToday: Boolean = false, val hasPartnerAnsweredToday: Boolean = false,
val coupleId: String? = null, val coupleId: String? = null,
@ -119,11 +123,13 @@ class PartnerHomeViewModel @Inject constructor(
return@launch return@launch
} }
val partnerId = couple.userIds.firstOrNull { it != uid } val partnerId = couple.userIds.firstOrNull { it != uid }
val partnerName = partnerId?.let { pid -> val partner = partnerId?.let { pid ->
runCatching { userRepository.getUser(pid)?.displayName } runCatching { userRepository.getUser(pid) }
.onFailure { Log.w(TAG, "Could not load partner name", it) } .onFailure { Log.w(TAG, "Could not load partner", it) }
.getOrNull() .getOrNull()
} }
val partnerName = partner?.displayName
val partnerPhotoUrl = partner?.photoUrl
val dailyAssignment = runCatching { val dailyAssignment = runCatching {
answerDataSource.getDailyQuestionAssignment(couple.id) answerDataSource.getDailyQuestionAssignment(couple.id)
}.getOrNull() }.getOrNull()
@ -132,6 +138,7 @@ class PartnerHomeViewModel @Inject constructor(
it.copy( it.copy(
isLoading = false, isLoading = false,
partnerName = partnerName, partnerName = partnerName,
partnerPhotoUrl = partnerPhotoUrl,
streakCount = couple.streakCount, streakCount = couple.streakCount,
coupleId = couple.id, coupleId = couple.id,
dailyQuestionId = dailyAssignment?.questionId, dailyQuestionId = dailyAssignment?.questionId,
@ -269,7 +276,7 @@ private fun PartnerHomeContent(
.padding(horizontal = 20.dp, vertical = 12.dp), .padding(horizontal = 20.dp, vertical = 12.dp),
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(16.dp)
) { ) {
PartnerIdentityCard(name = state.partnerName, streakCount = state.streakCount) PartnerIdentityCard(name = state.partnerName, photoUrl = state.partnerPhotoUrl, streakCount = state.streakCount)
PartnerActivityCard( PartnerActivityCard(
partnerName = state.partnerName, partnerName = state.partnerName,
@ -299,6 +306,7 @@ private fun PartnerHomeContent(
@Composable @Composable
private fun PartnerIdentityCard( private fun PartnerIdentityCard(
name: String?, name: String?,
photoUrl: String?,
streakCount: Int, streakCount: Int,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
@ -313,20 +321,31 @@ private fun PartnerIdentityCard(
horizontalArrangement = Arrangement.spacedBy(16.dp), horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Surface( if (!photoUrl.isNullOrBlank()) {
shape = CircleShape, AsyncImage(
color = CloserPalette.PurpleDeep.copy(alpha = 0.14f), model = photoUrl,
modifier = Modifier.size(56.dp) contentDescription = name,
) { contentScale = ContentScale.Crop,
Box(contentAlignment = Alignment.Center) { modifier = Modifier
Text( .size(56.dp)
text = (name?.firstOrNull()?.uppercaseChar() ?: '?').toString(), .clip(CircleShape)
style = MaterialTheme.typography.headlineMedium.copy( )
fontWeight = FontWeight.SemiBold, } else {
fontSize = 24.sp Surface(
), shape = CircleShape,
color = CloserPalette.PurpleDeep color = CloserPalette.PurpleDeep.copy(alpha = 0.14f),
) modifier = Modifier.size(56.dp)
) {
Box(contentAlignment = Alignment.Center) {
Text(
text = (name?.firstOrNull()?.uppercaseChar() ?: '?').toString(),
style = MaterialTheme.typography.headlineMedium.copy(
fontWeight = FontWeight.SemiBold,
fontSize = 24.sp
),
color = CloserPalette.PurpleDeep
)
}
} }
} }