mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 21:15:48 +00:00
Add rememberRecipientField composable function for reading live recipient fields.
This commit is contained in:
committed by
Cody Henthorne
parent
df170dac32
commit
7616ec1fd2
@@ -9,23 +9,16 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.rx3.asFlow
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView
|
||||
import org.thoughtcrime.securesms.database.model.ProfileAvatarFileDetails
|
||||
import org.thoughtcrime.securesms.profiles.AvatarHelper
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.NameUtil
|
||||
import org.thoughtcrime.securesms.recipients.rememberRecipientField
|
||||
|
||||
@Composable
|
||||
fun AvatarImage(
|
||||
@@ -41,15 +34,12 @@ fun AvatarImage(
|
||||
)
|
||||
} else {
|
||||
val context = LocalContext.current
|
||||
var state: AvatarImageState by remember {
|
||||
mutableStateOf(AvatarImageState(null, recipient, ProfileAvatarFileDetails.NO_DETAILS))
|
||||
}
|
||||
|
||||
LaunchedEffect(recipient.id) {
|
||||
Recipient.observable(recipient.id).asFlow()
|
||||
.collectLatest {
|
||||
state = AvatarImageState(NameUtil.getAbbreviation(it.getDisplayName(context)), it, AvatarHelper.getAvatarFileDetails(context, it.id))
|
||||
}
|
||||
val avatarImageState by rememberRecipientField(recipient) {
|
||||
AvatarImageState(
|
||||
getDisplayName(context),
|
||||
this,
|
||||
profileAvatarFileDetails
|
||||
)
|
||||
}
|
||||
|
||||
AndroidView(
|
||||
@@ -62,9 +52,9 @@ fun AvatarImage(
|
||||
modifier = modifier.background(color = Color.Transparent, shape = CircleShape)
|
||||
) {
|
||||
if (useProfile) {
|
||||
it.setAvatarUsingProfile(state.self)
|
||||
it.setAvatarUsingProfile(avatarImageState.self)
|
||||
} else {
|
||||
it.setAvatar(state.self)
|
||||
it.setAvatar(avatarImageState.self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,10 +67,6 @@ import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.rx3.asFlow
|
||||
import org.signal.core.ui.compose.DropdownMenus
|
||||
import org.signal.core.ui.compose.IconButtons
|
||||
import org.signal.core.ui.compose.Previews
|
||||
@@ -79,11 +75,11 @@ import org.signal.core.ui.compose.TextFields
|
||||
import org.signal.core.ui.compose.Tooltips
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.avatar.AvatarImage
|
||||
import org.thoughtcrime.securesms.badges.models.Badge
|
||||
import org.thoughtcrime.securesms.calls.log.CallLogFilter
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.BadgeImageSmall
|
||||
import org.thoughtcrime.securesms.conversationlist.model.ConversationFilter
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.rememberRecipientField
|
||||
|
||||
interface MainToolbarCallback {
|
||||
fun onNewGroupClick()
|
||||
@@ -353,16 +349,7 @@ private fun PrimaryToolbar(
|
||||
}
|
||||
)
|
||||
|
||||
var badge by remember { mutableStateOf<Badge?>(null) }
|
||||
LaunchedEffect(state.self.id) {
|
||||
Recipient.observable(state.self.id)
|
||||
.asFlow()
|
||||
.map { it.featuredBadge }
|
||||
.distinctUntilChanged()
|
||||
.collectLatest {
|
||||
badge = it
|
||||
}
|
||||
}
|
||||
val badge by rememberRecipientField(state.self) { featuredBadge }
|
||||
|
||||
BadgeImageSmall(
|
||||
badge = badge,
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.recipients
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import kotlinx.coroutines.rx3.asFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.signal.core.util.concurrent.SignalDispatchers
|
||||
|
||||
/**
|
||||
* Allows composable UI to subscribe to changes for a specific field on a recipient.
|
||||
*/
|
||||
@Composable
|
||||
fun <T> rememberRecipientField(recipient: Recipient, toField: Recipient.() -> T): State<T> {
|
||||
return rememberRecipientField(recipientId = recipient.id, initialData = recipient, toField = toField)
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows composable UI to subscribe to changes for a specific field on a recipient.
|
||||
*/
|
||||
@Composable
|
||||
fun <T> rememberRecipientField(recipientId: RecipientId, toField: Recipient.() -> T): State<T> {
|
||||
return rememberRecipientField(recipientId = recipientId, initialData = Recipient.UNKNOWN, toField = toField)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun <T> rememberRecipientField(recipientId: RecipientId, initialData: Recipient, toField: Recipient.() -> T): State<T> {
|
||||
var recipientAndCounter by remember(recipientId) { mutableStateOf(initialData to 0L) }
|
||||
|
||||
LaunchedEffect(recipientId) {
|
||||
withContext(SignalDispatchers.IO) {
|
||||
Recipient.observable(recipientId)
|
||||
.asFlow()
|
||||
.collect {
|
||||
recipientAndCounter = it to (recipientAndCounter.second + 1L)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return remember(recipientAndCounter) {
|
||||
derivedStateOf { toField(recipientAndCounter.first) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user