Fix avatar loading in OS views when app is not running.

This commit is contained in:
Cody Henthorne
2024-08-19 14:10:20 -04:00
committed by mtang-signal
parent 8a4d9fc635
commit 71b5a9f865
22 changed files with 384 additions and 439 deletions

View File

@@ -9,24 +9,15 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import com.annimon.stream.Stream;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.database.CallLinkTable;
import org.thoughtcrime.securesms.database.DistributionListTables;
import org.thoughtcrime.securesms.database.GroupTable;
import org.thoughtcrime.securesms.database.model.GroupRecord;
import org.thoughtcrime.securesms.database.RecipientTable;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.model.DistributionListRecord;
import org.thoughtcrime.securesms.database.model.RecipientRecord;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicReference;
@@ -198,62 +189,11 @@ public final class LiveRecipient {
}
private @NonNull Recipient fetchAndCacheRecipientFromDisk(@NonNull RecipientId id) {
RecipientRecord record = recipientTable.getRecord(id);
Recipient recipient;
if (record.getGroupId() != null) {
recipient = getGroupRecipientDetails(record);
} else if (record.getDistributionListId() != null) {
recipient = getDistributionListRecipientDetails(record);
} else if (record.getCallLinkRoomId() != null) {
recipient = getCallLinkRecipientDetails(record);
} else {
recipient = RecipientCreator.forIndividual(context, record);
}
Recipient recipient = RecipientCreator.forRecord(context, recipientTable.getRecord(id));
RecipientIdCache.INSTANCE.put(recipient);
return recipient;
}
@WorkerThread
private @NonNull Recipient getGroupRecipientDetails(@NonNull RecipientRecord record) {
Optional<GroupRecord> groupRecord = groupDatabase.getGroup(record.getId());
if (groupRecord.isPresent()) {
return RecipientCreator.forGroup(groupRecord.get(), record);
} else {
return RecipientCreator.forUnknownGroup(record.getId(), record.getGroupId());
}
}
@WorkerThread
private @NonNull Recipient getDistributionListRecipientDetails(@NonNull RecipientRecord record) {
DistributionListRecord groupRecord = distributionListTables.getList(Objects.requireNonNull(record.getDistributionListId()));
// TODO [stories] We'll have to see what the perf is like for very large distribution lists. We may not be able to support fetching all the members.
if (groupRecord != null) {
String title = groupRecord.isUnknown() ? null : groupRecord.getName();
List<RecipientId> members = Stream.of(groupRecord.getMembers()).filterNot(RecipientId::isUnknown).toList();
return RecipientCreator.forDistributionList(title, members, record);
}
return RecipientCreator.forDistributionList(null, null, record);
}
@WorkerThread
private @NonNull Recipient getCallLinkRecipientDetails(@NonNull RecipientRecord record) {
CallLinkTable.CallLink callLink = SignalDatabase.callLinks().getCallLinkByRoomId(Objects.requireNonNull(record.getCallLinkRoomId()));
if (callLink != null) {
String name = callLink.getState().getName();
return RecipientCreator.forCallLink(name, record, callLink.getAvatarColor());
}
return RecipientCreator.forCallLink(null, record, AvatarColor.UNKNOWN);
}
synchronized void set(@NonNull Recipient recipient) {
this.recipient.set(recipient);
this.liveData.postValue(recipient);

View File

@@ -2,8 +2,10 @@ package org.thoughtcrime.securesms.recipients
import android.content.Context
import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.GroupRecord
import org.thoughtcrime.securesms.database.model.RecipientRecord
import org.thoughtcrime.securesms.groups.GroupId
@@ -101,6 +103,22 @@ object RecipientCreator {
)
}
@JvmStatic
@WorkerThread
fun forRecord(context: Context, record: RecipientRecord): Recipient {
val recipient = if (record.groupId != null) {
getGroupRecipientDetails(record)
} else if (record.distributionListId != null) {
getDistributionListRecipientDetails(record)
} else if (record.callLinkRoomId != null) {
getCallLinkRecipientDetails(record)
} else {
forIndividual(context, record)
}
return recipient
}
@JvmStatic
fun forUnknown(): Recipient {
return Recipient.UNKNOWN
@@ -186,4 +204,43 @@ object RecipientCreator {
note = record.note
)
}
@WorkerThread
private fun getGroupRecipientDetails(record: RecipientRecord): Recipient {
val groupRecord = SignalDatabase.groups.getGroup(record.id)
return if (groupRecord.isPresent) {
forGroup(groupRecord.get(), record)
} else {
forUnknownGroup(record.id, record.groupId)
}
}
@WorkerThread
private fun getDistributionListRecipientDetails(record: RecipientRecord): Recipient {
val groupRecord = SignalDatabase.distributionLists.getList(record.distributionListId!!)
// TODO [stories] We'll have to see what the perf is like for very large distribution lists. We may not be able to support fetching all the members.
if (groupRecord != null) {
val title = if (groupRecord.isUnknown) null else groupRecord.name
val members = groupRecord.members.filterNot { it.isUnknown }
return forDistributionList(title, members, record)
}
return forDistributionList(null, null, record)
}
@WorkerThread
private fun getCallLinkRecipientDetails(record: RecipientRecord): Recipient {
val callLink = SignalDatabase.callLinks.getCallLinkByRoomId(record.callLinkRoomId!!)
if (callLink != null) {
val name = callLink.state.name
return forCallLink(name, record, callLink.avatarColor)
}
return forCallLink(null, record, AvatarColor.UNKNOWN)
}
}