mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-26 06:07:32 +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;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -32,6 +33,7 @@ public final class LiveRecipient {
|
|||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final MutableLiveData<Recipient> liveData;
|
private final MutableLiveData<Recipient> liveData;
|
||||||
|
private final LiveData<Recipient> observableLiveData;
|
||||||
private final Set<RecipientForeverObserver> observers;
|
private final Set<RecipientForeverObserver> observers;
|
||||||
private final Observer<Recipient> foreverObserver;
|
private final Observer<Recipient> foreverObserver;
|
||||||
private final AtomicReference<Recipient> recipient;
|
private final AtomicReference<Recipient> recipient;
|
||||||
@@ -50,6 +52,7 @@ public final class LiveRecipient {
|
|||||||
o.onRecipientChanged(recipient);
|
o.onRecipientChanged(recipient);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
this.observableLiveData = LiveDataUtil.distinctUntilChanged(liveData, Recipient::hasSameContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull RecipientId getId() {
|
public @NonNull RecipientId getId() {
|
||||||
@@ -70,14 +73,14 @@ public final class LiveRecipient {
|
|||||||
* use {@link #removeObservers(LifecycleOwner)}.
|
* use {@link #removeObservers(LifecycleOwner)}.
|
||||||
*/
|
*/
|
||||||
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<Recipient> observer) {
|
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.
|
* Removes all observers of this data registered for the given LifecycleOwner.
|
||||||
*/
|
*/
|
||||||
public void removeObservers(@NonNull LifecycleOwner owner) {
|
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) {
|
public void observeForever(@NonNull RecipientForeverObserver observer) {
|
||||||
Util.postToMain(() -> {
|
Util.postToMain(() -> {
|
||||||
if (observers.isEmpty()) {
|
if (observers.isEmpty()) {
|
||||||
liveData.observeForever(foreverObserver);
|
observableLiveData.observeForever(foreverObserver);
|
||||||
}
|
}
|
||||||
observers.add(observer);
|
observers.add(observer);
|
||||||
});
|
});
|
||||||
@@ -102,7 +105,7 @@ public final class LiveRecipient {
|
|||||||
observers.remove(observer);
|
observers.remove(observer);
|
||||||
|
|
||||||
if (observers.isEmpty()) {
|
if (observers.isEmpty()) {
|
||||||
liveData.removeObserver(foreverObserver);
|
observableLiveData.removeObserver(foreverObserver);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -172,7 +175,7 @@ public final class LiveRecipient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull LiveData<Recipient> getLiveData() {
|
public @NonNull LiveData<Recipient> getLiveData() {
|
||||||
return liveData;
|
return observableLiveData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull Recipient fetchAndCacheRecipientFromDisk(@NonNull RecipientId id) {
|
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 org.whispersystems.signalservice.api.util.UuidUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@@ -873,6 +874,12 @@ public class Recipient {
|
|||||||
return id.equals(recipient.id);
|
return id.equals(recipient.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public enum Capability {
|
public enum Capability {
|
||||||
UNKNOWN(0),
|
UNKNOWN(0),
|
||||||
SUPPORTED(1),
|
SUPPORTED(1),
|
||||||
@@ -902,11 +909,64 @@ public class Recipient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public boolean hasSameContent(@NonNull Recipient other) {
|
||||||
public int hashCode() {
|
return Objects.equals(id, other.id) &&
|
||||||
return Objects.hash(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 static class FallbackPhotoProvider {
|
||||||
public @NonNull FallbackContactPhoto getPhotoForLocalNumber() {
|
public @NonNull FallbackContactPhoto getPhotoForLocalNumber() {
|
||||||
return new ResourceContactPhoto(R.drawable.ic_note_34, R.drawable.ic_note_24);
|
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.LiveData;
|
||||||
import androidx.lifecycle.MediatorLiveData;
|
import androidx.lifecycle.MediatorLiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
import androidx.lifecycle.Observer;
|
||||||
|
|
||||||
import com.annimon.stream.function.Predicate;
|
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> {
|
public interface Combine<A, B, R> {
|
||||||
@NonNull R apply(@NonNull A a, @NonNull B b);
|
@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 static final class CombineLiveData<A, B, R> extends MediatorLiveData<R> {
|
||||||
private A a;
|
private A a;
|
||||||
private B b;
|
private B b;
|
||||||
|
Reference in New Issue
Block a user