mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-25 19:29:30 +00:00
Only notify for actual recipient changes.
This commit is contained in:
@@ -18,6 +18,7 @@ import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.util.List;
|
||||
@@ -32,6 +33,7 @@ public final class LiveRecipient {
|
||||
|
||||
private final Context context;
|
||||
private final MutableLiveData<Recipient> liveData;
|
||||
private final LiveData<Recipient> observableLiveData;
|
||||
private final Set<RecipientForeverObserver> observers;
|
||||
private final Observer<Recipient> foreverObserver;
|
||||
private final AtomicReference<Recipient> recipient;
|
||||
@@ -50,6 +52,7 @@ public final class LiveRecipient {
|
||||
o.onRecipientChanged(recipient);
|
||||
}
|
||||
};
|
||||
this.observableLiveData = LiveDataUtil.distinctUntilChanged(liveData, Recipient::hasSameContent);
|
||||
}
|
||||
|
||||
public @NonNull RecipientId getId() {
|
||||
@@ -70,14 +73,14 @@ public final class LiveRecipient {
|
||||
* use {@link #removeObservers(LifecycleOwner)}.
|
||||
*/
|
||||
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<Recipient> observer) {
|
||||
Util.postToMain(() -> liveData.observe(owner, observer));
|
||||
Util.postToMain(() -> observableLiveData.observe(owner, observer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all observers of this data registered for the given LifecycleOwner.
|
||||
*/
|
||||
public void removeObservers(@NonNull LifecycleOwner owner) {
|
||||
Util.runOnMain(() -> liveData.removeObservers(owner));
|
||||
Util.runOnMain(() -> observableLiveData.removeObservers(owner));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,7 +91,7 @@ public final class LiveRecipient {
|
||||
public void observeForever(@NonNull RecipientForeverObserver observer) {
|
||||
Util.postToMain(() -> {
|
||||
if (observers.isEmpty()) {
|
||||
liveData.observeForever(foreverObserver);
|
||||
observableLiveData.observeForever(foreverObserver);
|
||||
}
|
||||
observers.add(observer);
|
||||
});
|
||||
@@ -102,7 +105,7 @@ public final class LiveRecipient {
|
||||
observers.remove(observer);
|
||||
|
||||
if (observers.isEmpty()) {
|
||||
liveData.removeObserver(foreverObserver);
|
||||
observableLiveData.removeObserver(foreverObserver);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -172,7 +175,7 @@ public final class LiveRecipient {
|
||||
}
|
||||
|
||||
public @NonNull LiveData<Recipient> getLiveData() {
|
||||
return liveData;
|
||||
return observableLiveData;
|
||||
}
|
||||
|
||||
private @NonNull Recipient fetchAndCacheRecipientFromDisk(@NonNull RecipientId id) {
|
||||
|
@@ -47,6 +47,7 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
@@ -873,6 +874,12 @@ public class Recipient {
|
||||
return id.equals(recipient.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
|
||||
public enum Capability {
|
||||
UNKNOWN(0),
|
||||
SUPPORTED(1),
|
||||
@@ -902,11 +909,64 @@ public class Recipient {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
public boolean hasSameContent(@NonNull Recipient other) {
|
||||
return Objects.equals(id, other.id) &&
|
||||
resolving == other.resolving &&
|
||||
isSelf == other.isSelf &&
|
||||
blocked == other.blocked &&
|
||||
muteUntil == other.muteUntil &&
|
||||
expireMessages == other.expireMessages &&
|
||||
hasProfileImage == other.hasProfileImage &&
|
||||
profileSharing == other.profileSharing &&
|
||||
lastProfileFetch == other.lastProfileFetch &&
|
||||
forceSmsSelection == other.forceSmsSelection &&
|
||||
Objects.equals(id, other.id) &&
|
||||
Objects.equals(uuid, other.uuid) &&
|
||||
Objects.equals(username, other.username) &&
|
||||
Objects.equals(e164, other.e164) &&
|
||||
Objects.equals(email, other.email) &&
|
||||
Objects.equals(groupId, other.groupId) &&
|
||||
allContentsAreTheSame(participants, other.participants) &&
|
||||
Objects.equals(groupAvatarId, other.groupAvatarId) &&
|
||||
messageVibrate == other.messageVibrate &&
|
||||
callVibrate == other.callVibrate &&
|
||||
Objects.equals(messageRingtone, other.messageRingtone) &&
|
||||
Objects.equals(callRingtone, other.callRingtone) &&
|
||||
color == other.color &&
|
||||
Objects.equals(defaultSubscriptionId, other.defaultSubscriptionId) &&
|
||||
registered == other.registered &&
|
||||
Arrays.equals(profileKey, other.profileKey) &&
|
||||
Objects.equals(profileKeyCredential, other.profileKeyCredential) &&
|
||||
Objects.equals(name, other.name) &&
|
||||
Objects.equals(systemContactPhoto, other.systemContactPhoto) &&
|
||||
Objects.equals(customLabel, other.customLabel) &&
|
||||
Objects.equals(contactUri, other.contactUri) &&
|
||||
Objects.equals(profileName, other.profileName) &&
|
||||
Objects.equals(profileAvatar, other.profileAvatar) &&
|
||||
Objects.equals(notificationChannel, other.notificationChannel) &&
|
||||
unidentifiedAccessMode == other.unidentifiedAccessMode &&
|
||||
groupsV2Capability == other.groupsV2Capability &&
|
||||
groupsV1MigrationCapability == other.groupsV1MigrationCapability &&
|
||||
insightsBannerTier == other.insightsBannerTier &&
|
||||
Arrays.equals(storageId, other.storageId) &&
|
||||
mentionSetting == other.mentionSetting;
|
||||
}
|
||||
|
||||
private static boolean allContentsAreTheSame(@NonNull List<Recipient> a, @NonNull List<Recipient> b) {
|
||||
if (a.size() != b.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0, len = a.size(); i < len; i++) {
|
||||
if (!a.get(i).hasSameContent(b.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static class FallbackPhotoProvider {
|
||||
public @NonNull FallbackContactPhoto getPhotoForLocalNumber() {
|
||||
return new ResourceContactPhoto(R.drawable.ic_note_34, R.drawable.ic_note_24);
|
||||
|
@@ -7,6 +7,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MediatorLiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import com.annimon.stream.function.Predicate;
|
||||
|
||||
@@ -169,10 +170,42 @@ public final class LiveDataUtil {
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> LiveData<T> distinctUntilChanged(@NonNull LiveData<T> source, @NonNull EqualityChecker<T> checker) {
|
||||
final MediatorLiveData<T> outputLiveData = new MediatorLiveData<>();
|
||||
outputLiveData.addSource(source, new Observer<T>() {
|
||||
|
||||
boolean firstChange = true;
|
||||
|
||||
@Override
|
||||
public void onChanged(T nextValue) {
|
||||
T currentValue = outputLiveData.getValue();
|
||||
|
||||
if (currentValue == null && nextValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstChange ||
|
||||
currentValue == null ||
|
||||
nextValue == null ||
|
||||
!checker.contentsMatch(currentValue, nextValue))
|
||||
{
|
||||
firstChange = false;
|
||||
outputLiveData.setValue(nextValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return outputLiveData;
|
||||
}
|
||||
|
||||
public interface Combine<A, B, R> {
|
||||
@NonNull R apply(@NonNull A a, @NonNull B b);
|
||||
}
|
||||
|
||||
public interface EqualityChecker<T> {
|
||||
boolean contentsMatch(@NonNull T current, @NonNull T next);
|
||||
}
|
||||
|
||||
private static final class CombineLiveData<A, B, R> extends MediatorLiveData<R> {
|
||||
private A a;
|
||||
private B b;
|
||||
|
Reference in New Issue
Block a user