Fix conversation jumping when loading at last scroll position.

This commit is contained in:
Alex Hart 2020-06-12 17:23:40 -03:00 committed by Greyson Parrelli
parent cf98a22269
commit f2fe81d9b5
3 changed files with 37 additions and 6 deletions

View File

@ -424,7 +424,6 @@ public class ConversationFragment extends Fragment {
this.threadId = this.getActivity().getIntent().getLongExtra(ConversationActivity.THREAD_ID_EXTRA, -1); this.threadId = this.getActivity().getIntent().getLongExtra(ConversationActivity.THREAD_ID_EXTRA, -1);
this.unknownSenderView = new UnknownSenderView(getActivity(), recipient.get(), threadId, () -> clearHeaderIfNotTyping(getListAdapter())); this.unknownSenderView = new UnknownSenderView(getActivity(), recipient.get(), threadId, () -> clearHeaderIfNotTyping(getListAdapter()));
snapToTopDataObserver.requestScrollPosition(startingPosition);
conversationViewModel.onConversationDataAvailable(threadId, startingPosition); conversationViewModel.onConversationDataAvailable(threadId, startingPosition);
OnScrollListener scrollListener = new ConversationScrollListener(getActivity()); OnScrollListener scrollListener = new ConversationScrollListener(getActivity());
@ -966,7 +965,12 @@ public class ConversationFragment extends Fragment {
private void moveToMessagePosition(int position, @Nullable Runnable onMessageNotFound) { private void moveToMessagePosition(int position, @Nullable Runnable onMessageNotFound) {
conversationViewModel.onConversationDataAvailable(threadId, position); conversationViewModel.onConversationDataAvailable(threadId, position);
snapToTopDataObserver.buildScrollPosition(position) snapToTopDataObserver.buildScrollPosition(position)
.withOnScrollRequestComplete(() -> getListAdapter().pulseHighlightItem(position)) .withOnPerformScroll(((layoutManager, p) ->
list.post(() -> {
layoutManager.scrollToPosition(p);
getListAdapter().pulseHighlightItem(position);
})
))
.withOnInvalidPosition(() -> { .withOnInvalidPosition(() -> {
if (onMessageNotFound != null) { if (onMessageNotFound != null) {
onMessageNotFound.run(); onMessageNotFound.run();

View File

@ -17,10 +17,12 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mediasend.Media; import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mediasend.MediaRepository; import org.thoughtcrime.securesms.mediasend.MediaRepository;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.thoughtcrime.securesms.util.paging.Invalidator; import org.thoughtcrime.securesms.util.paging.Invalidator;
import org.whispersystems.libsignal.util.Pair; import org.whispersystems.libsignal.util.Pair;
import java.util.List; import java.util.List;
import java.util.Objects;
class ConversationViewModel extends ViewModel { class ConversationViewModel extends ViewModel {
@ -81,9 +83,11 @@ class ConversationViewModel extends ViewModel {
this.messages = Transformations.map(messagesForThreadId, Pair::second); this.messages = Transformations.map(messagesForThreadId, Pair::second);
LiveData<Long> distinctThread = Transformations.distinctUntilChanged(Transformations.map(messagesForThreadId, Pair::first)); LiveData<DistinctConversationDataByThreadId> distinctData = LiveDataUtil.combineLatest(messagesForThreadId,
metadata,
(m, data) -> new DistinctConversationDataByThreadId(data));
conversationMetadata = Transformations.switchMap(distinctThread, thread -> metadata); conversationMetadata = Transformations.map(Transformations.distinctUntilChanged(distinctData), DistinctConversationDataByThreadId::getConversationData);
} }
void onAttachmentKeyboardOpen() { void onAttachmentKeyboardOpen() {
@ -130,4 +134,29 @@ class ConversationViewModel extends ViewModel {
return modelClass.cast(new ConversationViewModel()); return modelClass.cast(new ConversationViewModel());
} }
} }
private static class DistinctConversationDataByThreadId {
private final ConversationData conversationData;
private DistinctConversationDataByThreadId(@NonNull ConversationData conversationData) {
this.conversationData = conversationData;
}
public @NonNull ConversationData getConversationData() {
return conversationData;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DistinctConversationDataByThreadId that = (DistinctConversationDataByThreadId) o;
return Objects.equals(conversationData.getThreadId(), that.conversationData.getThreadId());
}
@Override
public int hashCode() {
return Objects.hash(conversationData.getThreadId());
}
}
} }

View File

@ -77,10 +77,8 @@ public class SnapToTopDataObserver extends RecyclerView.AdapterDataObserver {
if (!scrollRequestValidator.isPositionStillValid(position)) { if (!scrollRequestValidator.isPositionStillValid(position)) {
onInvalidPosition.run(); onInvalidPosition.run();
} else if (scrollRequestValidator.isItemAtPositionLoaded(position)) { } else if (scrollRequestValidator.isItemAtPositionLoaded(position)) {
recyclerView.post(() -> {
onPerformScroll.onPerformScroll(layoutManager, position); onPerformScroll.onPerformScroll(layoutManager, position);
onScrollRequestComplete.run(); onScrollRequestComplete.run();
});
} else { } else {
deferred.setDeferred(true); deferred.setDeferred(true);
deferred.defer(() -> requestScrollPositionInternal(position, onPerformScroll, onScrollRequestComplete, onInvalidPosition)); deferred.defer(() -> requestScrollPositionInternal(position, onPerformScroll, onScrollRequestComplete, onInvalidPosition));