kopia lustrzana https://github.com/ryukoposting/Signal-Android
Move mms and security checks into ViewModel/Repository.
rodzic
c5f4a9c89e
commit
b696a0f758
|
@ -328,6 +328,10 @@ import java.util.concurrent.TimeoutException;
|
|||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import io.reactivex.rxjava3.core.Flowable;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
|
||||
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||
|
||||
/**
|
||||
|
@ -454,13 +458,12 @@ public class ConversationParentFragment extends Fragment
|
|||
private boolean isSecureText;
|
||||
private boolean isDefaultSms;
|
||||
private int reactWithAnyEmojiStartPage = -1;
|
||||
private boolean isMmsEnabled = true;
|
||||
private boolean isSecurityInitialized = false;
|
||||
private boolean isSearchRequested = false;
|
||||
private boolean hasProcessedShareData = false;
|
||||
|
||||
private final LifecycleDisposable disposables = new LifecycleDisposable();
|
||||
private final Debouncer optionsMenuDebouncer = new Debouncer(50);
|
||||
private final LifecycleDisposable disposables = new LifecycleDisposable();
|
||||
private final Debouncer optionsMenuDebouncer = new Debouncer(50);
|
||||
|
||||
private IdentityRecordList identityRecords = new IdentityRecordList(Collections.emptyList());
|
||||
private Callback callback;
|
||||
|
@ -528,8 +531,6 @@ public class ConversationParentFragment extends Fragment
|
|||
.commitNow();
|
||||
}
|
||||
|
||||
final boolean typingIndicatorsEnabled = TextSecurePreferences.isTypingIndicatorsEnabled(requireContext());
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
hasProcessedShareData = savedInstanceState.getBoolean("SHARED", false);
|
||||
}
|
||||
|
@ -549,45 +550,14 @@ public class ConversationParentFragment extends Fragment
|
|||
initializeEnabledCheck();
|
||||
initializePendingRequestsBanner();
|
||||
initializeGroupV1MigrationsBanners();
|
||||
initializeSecurity(recipient.get().isRegistered(), isDefaultSms).addListener(new AssertedSuccessListener<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(Boolean result) {
|
||||
if (getActivity() == null) {
|
||||
Log.w(TAG, "Activity is not attached. Not proceeding with initialization.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (requireActivity().isFinishing()) {
|
||||
Log.w(TAG, "Activity is finishing. Not proceeding with initialization.");
|
||||
return;
|
||||
}
|
||||
Flowable<ConversationSecurityInfo> observableSecurityInfo = viewModel.getConversationState()
|
||||
.map(ConversationState::getSecurityInfo)
|
||||
.filter(ConversationSecurityInfo::isInitialized);
|
||||
|
||||
initializeProfiles();
|
||||
initializeGv1Migration();
|
||||
disposables.add(observableSecurityInfo.subscribe(securityInfo -> handleSecurityChange(securityInfo.isPushAvailable(), securityInfo.isDefaultSmsApplication())));
|
||||
disposables.add(viewModel.getConversationSecurityInfo(args.getRecipientId()).firstOrError().subscribe(unused -> onInitialSecurityConfigurationLoaded()));
|
||||
|
||||
Log.d(TAG, "Initializing data from onViewCreated...");
|
||||
initializeDraft(args).addListener(new AssertedSuccessListener<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(Boolean loadedDraft) {
|
||||
if (loadedDraft != null && loadedDraft) {
|
||||
Log.i(TAG, "Finished loading draft");
|
||||
ThreadUtil.runOnMain(() -> {
|
||||
if (fragment != null && fragment.isResumed()) {
|
||||
fragment.moveToLastSeen();
|
||||
} else {
|
||||
Log.w(TAG, "Wanted to move to the last seen position, but the fragment was in an invalid state");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (typingIndicatorsEnabled) {
|
||||
composeText.addTextChangedListener(typingTextWatcher);
|
||||
}
|
||||
composeText.setSelection(composeText.length(), composeText.length());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
initializeInsightObserver();
|
||||
initializeActionBar();
|
||||
|
||||
|
@ -616,7 +586,7 @@ public class ConversationParentFragment extends Fragment
|
|||
WindowUtil.setLightStatusBarFromTheme(requireActivity());
|
||||
|
||||
EventBus.getDefault().register(this);
|
||||
initializeMmsEnabledCheck();
|
||||
viewModel.checkIfMmsIsEnabled();
|
||||
initializeIdentityRecords();
|
||||
composeText.setMessageSendType(sendButton.getSelectedSendType());
|
||||
|
||||
|
@ -758,7 +728,7 @@ public class ConversationParentFragment extends Fragment
|
|||
attachmentManager.setLocation(place, getCurrentMediaConstraints());
|
||||
break;
|
||||
case SMS_DEFAULT:
|
||||
initializeSecurity(isSecureText, isDefaultSms);
|
||||
viewModel.updateSecurityInfo();
|
||||
break;
|
||||
case PICK_GIF:
|
||||
case MEDIA_SENDER:
|
||||
|
@ -845,6 +815,38 @@ public class ConversationParentFragment extends Fragment
|
|||
}
|
||||
}
|
||||
|
||||
private void onInitialSecurityConfigurationLoaded() {
|
||||
Log.d(TAG, "Initial security configuration loaded.");
|
||||
if (isDetached()) {
|
||||
Log.w(TAG, "Fragment has become detached. Ignoring configuration call.");
|
||||
}
|
||||
|
||||
initializeProfiles();
|
||||
initializeGv1Migration();
|
||||
|
||||
Log.d(TAG, "Initializing draft from initial security configuration load...");
|
||||
initializeDraft(viewModel.getArgs()).addListener(new AssertedSuccessListener<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(Boolean loadedDraft) {
|
||||
if (loadedDraft != null && loadedDraft) {
|
||||
Log.i(TAG, "Finished loading draft");
|
||||
ThreadUtil.runOnMain(() -> {
|
||||
if (fragment != null && fragment.isResumed()) {
|
||||
fragment.moveToLastSeen();
|
||||
} else {
|
||||
Log.w(TAG, "Wanted to move to the last seen position, but the fragment was in an invalid state");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (TextSecurePreferences.isTypingIndicatorsEnabled(requireContext())) {
|
||||
composeText.addTextChangedListener(typingTextWatcher);
|
||||
}
|
||||
composeText.setSelection(composeText.length(), composeText.length());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setVisibleThread(long threadId) {
|
||||
if (!isInBubble()) {
|
||||
// TODO [alex] LargeScreenSupport -- Inform MainActivityViewModel that the conversation was opened.
|
||||
|
@ -1489,7 +1491,7 @@ public class ConversationParentFragment extends Fragment
|
|||
}
|
||||
|
||||
private void handleAddAttachment() {
|
||||
if (this.isMmsEnabled || isSecureText) {
|
||||
if (viewModel.getConversationStateSnapshot().isMmsEnabled() || isSecureText) {
|
||||
viewModel.getRecentMedia().removeObservers(this);
|
||||
|
||||
if (attachmentKeyboardStub.resolved() && container.isInputOpen() && container.getCurrentInput() == attachmentKeyboardStub.get()) {
|
||||
|
@ -1598,6 +1600,7 @@ public class ConversationParentFragment extends Fragment
|
|||
calculateCharactersRemaining();
|
||||
invalidateOptionsMenu();
|
||||
setBlockedUserState(recipient.get(), isSecureText, isDefaultSms);
|
||||
onSecurityUpdated();
|
||||
}
|
||||
|
||||
///// Initializers
|
||||
|
@ -1643,6 +1646,7 @@ public class ConversationParentFragment extends Fragment
|
|||
}
|
||||
|
||||
if (draftText != null) {
|
||||
Log.d(TAG, "Handling shared text");
|
||||
composeText.setText("");
|
||||
composeText.append(draftText);
|
||||
result.set(true);
|
||||
|
@ -1654,6 +1658,7 @@ public class ConversationParentFragment extends Fragment
|
|||
}
|
||||
|
||||
if (draftText == null && draftMedia == null && draftMediaType == null) {
|
||||
Log.d(TAG, "Initializing draft from database");
|
||||
return initializeDraftFromDatabase();
|
||||
} else {
|
||||
updateToggleButtonState();
|
||||
|
@ -1844,60 +1849,6 @@ public class ConversationParentFragment extends Fragment
|
|||
return future;
|
||||
}
|
||||
|
||||
private ListenableFuture<Boolean> initializeSecurity(final boolean currentSecureText,
|
||||
final boolean currentIsDefaultSms)
|
||||
{
|
||||
final SettableFuture<Boolean> future = new SettableFuture<>();
|
||||
final Context context = requireContext().getApplicationContext();
|
||||
|
||||
handleSecurityChange(currentSecureText || isPushGroupConversation(), currentIsDefaultSms);
|
||||
|
||||
new AsyncTask<Recipient, Void, boolean[]>() {
|
||||
@Override
|
||||
protected boolean[] doInBackground(Recipient... params) {
|
||||
Recipient recipient = params[0].resolve();
|
||||
Log.i(TAG, "Resolving registered state...");
|
||||
RegisteredState registeredState;
|
||||
|
||||
if (recipient.isPushGroup()) {
|
||||
Log.i(TAG, "Push group recipient...");
|
||||
registeredState = RegisteredState.REGISTERED;
|
||||
} else {
|
||||
Log.i(TAG, "Checking through resolved recipient");
|
||||
registeredState = recipient.resolve().getRegistered();
|
||||
}
|
||||
|
||||
Log.i(TAG, "Resolved registered state: " + registeredState);
|
||||
boolean signalEnabled = Recipient.self().isRegistered();
|
||||
|
||||
if (registeredState == RegisteredState.UNKNOWN) {
|
||||
try {
|
||||
Log.i(TAG, "Refreshing directory for user: " + recipient.getId().serialize());
|
||||
registeredState = ContactDiscovery.refresh(context, recipient, false);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
Log.i(TAG, "Returning registered state...");
|
||||
return new boolean[] {registeredState == RegisteredState.REGISTERED && signalEnabled,
|
||||
Util.isDefaultSmsProvider(context)};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(boolean[] result) {
|
||||
if (result[0] != currentSecureText || result[1] != currentIsDefaultSms) {
|
||||
Log.i(TAG, "onPostExecute() handleSecurityChange: " + result[0] + " , " + result[1]);
|
||||
handleSecurityChange(result[0], result[1]);
|
||||
}
|
||||
future.set(true);
|
||||
onSecurityUpdated();
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient.get());
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
private void onSecurityUpdated() {
|
||||
Log.i(TAG, "onSecurityUpdated()");
|
||||
updateReminders();
|
||||
|
@ -1989,22 +1940,6 @@ public class ConversationParentFragment extends Fragment
|
|||
sendButton.setDefaultSubscriptionId(defaultSubscriptionId.orElse(null));
|
||||
}
|
||||
|
||||
private void initializeMmsEnabledCheck() {
|
||||
final Context context = requireContext().getApplicationContext();
|
||||
|
||||
new AsyncTask<Void, Void, Boolean>() {
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
return Util.isMmsCapable(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean isMmsEnabled) {
|
||||
ConversationParentFragment.this.isMmsEnabled = isMmsEnabled;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private ListenableFuture<Boolean> initializeIdentityRecords() {
|
||||
final SettableFuture<Boolean> future = new SettableFuture<>();
|
||||
final Context context = requireContext().getApplicationContext();
|
||||
|
@ -2594,7 +2529,6 @@ public class ConversationParentFragment extends Fragment
|
|||
updateDefaultSubscriptionId(recipient.getDefaultSubscriptionId());
|
||||
updatePaymentsAvailable();
|
||||
updateSendButtonColor(sendButton.getSelectedSendType());
|
||||
initializeSecurity(isSecureText, isDefaultSms);
|
||||
|
||||
if (searchViewItem == null || !searchViewItem.isActionViewExpanded()) {
|
||||
invalidateOptionsMenu();
|
||||
|
@ -2658,7 +2592,7 @@ public class ConversationParentFragment extends Fragment
|
|||
securityUpdateReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
initializeSecurity(isSecureText, isDefaultSms);
|
||||
viewModel.updateSecurityInfo();
|
||||
calculateCharactersRemaining();
|
||||
}
|
||||
};
|
||||
|
@ -3024,7 +2958,7 @@ public class ConversationParentFragment extends Fragment
|
|||
|
||||
Log.i(TAG, "[sendMessage] recipient: " + recipient.getId() + ", threadId: " + threadId + ", sendType: " + (sendType.usesSignalTransport() ? "signal" : "sms") + ", isManual: " + sendButton.isManualSelection());
|
||||
|
||||
if ((recipient.isMmsGroup() || recipient.getEmail().isPresent()) && !isMmsEnabled) {
|
||||
if ((recipient.isMmsGroup() || recipient.getEmail().isPresent()) && !viewModel.getConversationStateSnapshot().isMmsEnabled()) {
|
||||
handleManualMmsRequired();
|
||||
} else if (sendType.usesSignalTransport() && (identityRecords.isUnverified(true) || identityRecords.isUntrusted(true))) {
|
||||
handleRecentSafetyNumberChange();
|
||||
|
|
|
@ -8,23 +8,33 @@ import androidx.annotation.WorkerThread;
|
|||
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceViewedUpdateJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
import org.thoughtcrime.securesms.util.BubbleUtil;
|
||||
import org.thoughtcrime.securesms.util.ConversationUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.core.Scheduler;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
class ConversationRepository {
|
||||
|
||||
private static final String TAG = Log.tag(ConversationRepository.class);
|
||||
|
@ -115,4 +125,41 @@ class ConversationRepository {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull Single<Boolean> checkIfMmsIsEnabled() {
|
||||
return Single.fromCallable(() -> Util.isMmsCapable(context)).subscribeOn(Schedulers.io());
|
||||
}
|
||||
|
||||
@NonNull Observable<ConversationSecurityInfo> getSecurityInfo(RecipientId recipientId) {
|
||||
return Recipient.observable(recipientId).map(recipient -> {
|
||||
Log.i(TAG, "Resolving registered state...");
|
||||
RecipientDatabase.RegisteredState registeredState;
|
||||
|
||||
if (recipient.isPushGroup()) {
|
||||
Log.i(TAG, "Push group recipient...");
|
||||
registeredState = RecipientDatabase.RegisteredState.REGISTERED;
|
||||
} else {
|
||||
Log.i(TAG, "Checking through resolved recipient");
|
||||
registeredState = recipient.resolve().getRegistered();
|
||||
}
|
||||
|
||||
Log.i(TAG, "Resolved registered state: " + registeredState);
|
||||
boolean signalEnabled = Recipient.self().isRegistered();
|
||||
|
||||
if (registeredState == RecipientDatabase.RegisteredState.UNKNOWN) {
|
||||
try {
|
||||
Log.i(TAG, "Refreshing directory for user: " + recipient.getId().serialize());
|
||||
registeredState = ContactDiscovery.refresh(context, recipient, false);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
Log.i(TAG, "Returning registered state...");
|
||||
return new ConversationSecurityInfo(recipientId,
|
||||
registeredState == RecipientDatabase.RegisteredState.REGISTERED && signalEnabled,
|
||||
Util.isDefaultSmsProvider(context),
|
||||
true);
|
||||
}).subscribeOn(Schedulers.io());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package org.thoughtcrime.securesms.conversation
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
|
||||
data class ConversationSecurityInfo(
|
||||
val recipientId: RecipientId = RecipientId.UNKNOWN,
|
||||
val isPushAvailable: Boolean = false,
|
||||
val isDefaultSmsApplication: Boolean = false,
|
||||
val isInitialized: Boolean = false
|
||||
)
|
|
@ -0,0 +1,21 @@
|
|||
package org.thoughtcrime.securesms.conversation
|
||||
|
||||
/**
|
||||
* State holder for different values we are interested in for a given
|
||||
* conversation. This is to be used for different values normally stored
|
||||
* directly in the fragment that would be better relegated to a ViewModel.
|
||||
*/
|
||||
data class ConversationState(
|
||||
val isMmsEnabled: Boolean = true,
|
||||
val securityInfo: ConversationSecurityInfo = ConversationSecurityInfo()
|
||||
) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun create(): ConversationState {
|
||||
return ConversationState()
|
||||
}
|
||||
}
|
||||
|
||||
fun withMmsEnabled(isMmsEnabled: Boolean) = copy(isMmsEnabled = isMmsEnabled)
|
||||
fun withSecurityInfo(securityInfo: ConversationSecurityInfo) = copy(securityInfo = securityInfo)
|
||||
}
|
|
@ -17,12 +17,12 @@ import org.greenrobot.eventbus.EventBus;
|
|||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.libsignal.protocol.util.Pair;
|
||||
import org.signal.paging.ObservablePagedData;
|
||||
import org.signal.paging.PagedData;
|
||||
import org.signal.paging.PagingConfig;
|
||||
import org.signal.paging.PagingController;
|
||||
import org.signal.paging.ProxyPagingController;
|
||||
import org.signal.libsignal.protocol.util.Pair;
|
||||
import org.thoughtcrime.securesms.components.settings.app.notifications.profiles.NotificationProfilesRepository;
|
||||
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
|
||||
import org.thoughtcrime.securesms.conversation.colors.GroupAuthorNameColorHelper;
|
||||
|
@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.util.Util;
|
|||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||
import org.thoughtcrime.securesms.util.livedata.Store;
|
||||
import org.thoughtcrime.securesms.util.rx.RxStore;
|
||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
|
||||
|
||||
import java.util.Collections;
|
||||
|
@ -55,9 +56,12 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.core.BackpressureStrategy;
|
||||
import io.reactivex.rxjava3.core.Flowable;
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
import io.reactivex.rxjava3.subjects.BehaviorSubject;
|
||||
import kotlin.Unit;
|
||||
|
||||
public class ConversationViewModel extends ViewModel {
|
||||
|
||||
|
@ -88,6 +92,9 @@ public class ConversationViewModel extends ViewModel {
|
|||
private final NotificationProfilesRepository notificationProfilesRepository;
|
||||
private final MutableLiveData<String> searchQuery;
|
||||
private final GroupAuthorNameColorHelper groupAuthorNameColorHelper;
|
||||
private final RxStore<ConversationState> conversationStateStore;
|
||||
private final CompositeDisposable disposables;
|
||||
private final BehaviorSubject<Unit> conversationStateTick;
|
||||
|
||||
private ConversationIntents.Args args;
|
||||
private int jumpToPosition;
|
||||
|
@ -113,6 +120,9 @@ public class ConversationViewModel extends ViewModel {
|
|||
this.recipientId = BehaviorSubject.create();
|
||||
this.threadId = BehaviorSubject.create();
|
||||
this.groupAuthorNameColorHelper = new GroupAuthorNameColorHelper();
|
||||
this.conversationStateStore = new RxStore<>(ConversationState.create(), Schedulers.io());
|
||||
this.disposables = new CompositeDisposable();
|
||||
this.conversationStateTick = BehaviorSubject.createDefault(Unit.INSTANCE);
|
||||
|
||||
BehaviorSubject<Recipient> recipientCache = BehaviorSubject.create();
|
||||
|
||||
|
@ -122,6 +132,12 @@ public class ConversationViewModel extends ViewModel {
|
|||
.map(Recipient::resolved)
|
||||
.subscribe(recipientCache);
|
||||
|
||||
conversationStateStore.update(Observable.combineLatest(recipientId, conversationStateTick, (id, tick) -> id)
|
||||
.distinctUntilChanged()
|
||||
.switchMap(conversationRepository::getSecurityInfo)
|
||||
.toFlowable(BackpressureStrategy.LATEST),
|
||||
(securityInfo, state) -> state.withSecurityInfo(securityInfo));
|
||||
|
||||
BehaviorSubject<ConversationData> conversationMetadata = BehaviorSubject.create();
|
||||
|
||||
Observable.combineLatest(threadId, recipientCache, Pair::new)
|
||||
|
@ -270,6 +286,29 @@ public class ConversationViewModel extends ViewModel {
|
|||
conversationRepository.markGiftBadgeRevealed(messageId);
|
||||
}
|
||||
|
||||
void checkIfMmsIsEnabled() {
|
||||
disposables.add(conversationRepository.checkIfMmsIsEnabled().subscribe(isEnabled -> {
|
||||
conversationStateStore.update(state -> state.withMmsEnabled(true));
|
||||
}));
|
||||
}
|
||||
|
||||
@NonNull Flowable<ConversationState> getConversationState() {
|
||||
return conversationStateStore.getStateFlowable().observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
@NonNull Flowable<ConversationSecurityInfo> getConversationSecurityInfo(@NonNull RecipientId recipientId) {
|
||||
return getConversationState().map(ConversationState::getSecurityInfo)
|
||||
.filter(info -> info.isInitialized() && Objects.equals(info.getRecipientId(), recipientId));
|
||||
}
|
||||
|
||||
void updateSecurityInfo() {
|
||||
conversationStateTick.onNext(Unit.INSTANCE);
|
||||
}
|
||||
|
||||
@NonNull ConversationState getConversationStateSnapshot() {
|
||||
return conversationStateStore.getState();
|
||||
}
|
||||
|
||||
@NonNull LiveData<String> getSearchQuery() {
|
||||
return searchQuery;
|
||||
}
|
||||
|
@ -372,6 +411,7 @@ public class ConversationViewModel extends ViewModel {
|
|||
ApplicationDependencies.getDatabaseObserver().unregisterObserver(conversationObserver);
|
||||
ApplicationDependencies.getDatabaseObserver().unregisterObserver(messageUpdateObserver);
|
||||
ApplicationDependencies.getDatabaseObserver().unregisterObserver(messageInsertObserver);
|
||||
disposables.clear();
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,10 @@ class LifecycleDisposable : DefaultLifecycleObserver {
|
|||
return this
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
disposables.clear()
|
||||
}
|
||||
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
owner.lifecycle.removeObserver(this)
|
||||
disposables.clear()
|
||||
|
|
Ładowanie…
Reference in New Issue