Skip to content

Commit

Permalink
Fix jumping to last seen position.
Browse files Browse the repository at this point in the history
  • Loading branch information
greyson-signal authored and alex-signal committed May 14, 2020
1 parent 1778c1e commit 53d122e
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ public boolean onBackPressed() {
return false;
}

public void goToConversation(@NonNull RecipientId recipientId, long threadId, int distributionType, long lastSeen, int startingPosition) {
Intent intent = ConversationActivity.buildIntent(activity, recipientId, threadId, distributionType, lastSeen, startingPosition);
public void goToConversation(@NonNull RecipientId recipientId, long threadId, int distributionType, int startingPosition) {
Intent intent = ConversationActivity.buildIntent(activity, recipientId, threadId, distributionType, startingPosition);

activity.startActivity(intent);
activity.overridePendingTransition(R.anim.slide_from_end, R.anim.fade_scale_out);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity

public static final String RECIPIENT_EXTRA = "recipient_id";
public static final String THREAD_ID_EXTRA = "thread_id";
public static final String IS_ARCHIVED_EXTRA = "is_archived";
public static final String TEXT_EXTRA = "draft_text";
public static final String MEDIA_EXTRA = "media_list";
public static final String STICKER_EXTRA = "sticker_extra";
public static final String DISTRIBUTION_TYPE_EXTRA = "distribution_type";
public static final String LAST_SEEN_EXTRA = "last_seen";
public static final String STARTING_POSITION_EXTRA = "starting_position";

private static final int PICK_GALLERY = 1;
Expand Down Expand Up @@ -342,12 +340,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private LiveRecipient recipient;
private long threadId;
private int distributionType;
private boolean archived;
private boolean isSecureText;
private boolean isDefaultSms = true;
private boolean isMmsEnabled = true;
private boolean isSecurityInitialized = false;
private boolean shouldDisplayMessageRequestUi = true;

private final IdentityRecordList identityRecords = new IdentityRecordList();
private final DynamicTheme dynamicTheme = new DynamicDarkToolbarTheme();
Expand All @@ -357,14 +353,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@NonNull RecipientId recipientId,
long threadId,
int distributionType,
long lastSeen,
int startingPosition)
{
Intent intent = new Intent(context, ConversationActivity.class);
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipientId);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
intent.putExtra(ConversationActivity.LAST_SEEN_EXTRA, lastSeen);
intent.putExtra(ConversationActivity.STARTING_POSITION_EXTRA, startingPosition);

return intent;
Expand Down Expand Up @@ -1739,7 +1733,6 @@ private void initializeResources() {

recipient = Recipient.live(getIntent().getParcelableExtra(RECIPIENT_EXTRA));
threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
archived = getIntent().getBooleanExtra(IS_ARCHIVED_EXTRA, false);
distributionType = getIntent().getIntExtra(DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
glideRequests = GlideApp.with(this);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import androidx.annotation.AnyThread;
import androidx.annotation.LayoutRes;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.paging.PagedList;
Expand Down Expand Up @@ -241,16 +242,17 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi
@Override
public void submitList(@Nullable PagedList<MessageRecord> pagedList) {
cleanFastRecords();
super.submitList(pagedList);
notifyDataSetChanged();
super.submitList(pagedList, this::notifyDataSetChanged);
}

@Override
protected @Nullable MessageRecord getItem(int position) {
position = hasHeader() ? position - 1 : position;

if (position < fastRecords.size()) {
return fastRecords.get(position);
} else {
int correctedPosition = position - fastRecords.size() - (hasHeader() ? 1 : 0);
int correctedPosition = position - fastRecords.size();
return super.getItem(correctedPosition);
}
}
Expand Down Expand Up @@ -302,31 +304,19 @@ void onBindLastSeenViewHolder(StickyHeaderViewHolder viewHolder, int position) {
}

/**
* Given a timestamp, this will return the position in the adapter of the message with the
* nearest received timestamp, or -1 if none is found.
* The presence of a header may throw off the position you'd like to jump to. This will return
* an adjusted message position based on adapter state.
*/
int findLastSeenPosition(long lastSeen) {
if (lastSeen <= 0) {
return -1;
}

int count = getItemCount() - (hasFooter() ? 1 : 0);

for (int i = (hasHeader() ? 1 : 0); i < count; i++) {
MessageRecord messageRecord = getItem(i);

if (messageRecord == null || messageRecord.isOutgoing() || messageRecord.getDateReceived() <= lastSeen) {
return i;
}
}

return -1;
@MainThread
int getAdapterPositionForMessagePosition(int messagePosition) {
return hasHeader() ? messagePosition + 1 : messagePosition;
}

/**
* Finds the received timestamp for the item at the requested adapter position. Will return 0 if
* the position doesn't refer to an incoming message.
*/
@MainThread
long getReceivedTimestamp(int position) {
if (isHeaderPosition(position)) return 0;
if (isFooterPosition(position)) return 0;
Expand Down Expand Up @@ -385,8 +375,9 @@ void onSearchQueryUpdated(String query) {
* Adds a record to a memory cache to allow it to be rendered immediately, as opposed to waiting
* for a database change.
*/
@MainThread
void addFastRecord(MessageRecord record) {
fastRecords.add(record);
fastRecords.add(0, record);
notifyDataSetChanged();
}

Expand Down Expand Up @@ -426,6 +417,7 @@ void toggleSelection(MessageRecord record) {
}
}

@MainThread
private void cleanFastRecords() {
synchronized (releasedFastRecords) {
Iterator<MessageRecord> recordIterator = fastRecords.iterator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,34 @@
*/
final class ConversationData {
private final long lastSeen;
private final int lastSeenPosition;
private final boolean hasSent;
private final boolean isMessageRequestAccepted;
private final boolean hasPreMessageRequestMessages;
private final int jumpToPosition;

ConversationData(long lastSeen,
int lastSeenPosition,
boolean hasSent,
boolean isMessageRequestAccepted,
boolean hasPreMessageRequestMessages,
int jumpToPosition)
{
this.lastSeen = lastSeen;
this.lastSeenPosition = lastSeenPosition;
this.hasSent = hasSent;
this.isMessageRequestAccepted = isMessageRequestAccepted;
this.hasPreMessageRequestMessages = hasPreMessageRequestMessages;
this.jumpToPosition = jumpToPosition;
}

long getLastSeen() {
return lastSeen;
}
return lastSeen;
}

int getLastSeenPosition() {
return lastSeenPosition;
}

boolean hasSent() {
return hasSent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ public void onNewIntent() {
}

public void moveToLastSeen() {
if (conversationViewModel.getLastSeen() <= 0) {
if (conversationViewModel.getLastSeenPosition() <= 0) {
Log.i(TAG, "No need to move to last seen.");
return;
}
Expand All @@ -302,7 +302,7 @@ public void moveToLastSeen() {
return;
}

int position = getListAdapter().findLastSeenPosition(conversationViewModel.getLastSeen());
int position = getListAdapter().getAdapterPositionForMessagePosition(conversationViewModel.getLastSeenPosition());
scrollToLastSeenPosition(position);
}

Expand Down Expand Up @@ -391,14 +391,13 @@ private static void presentMessageRequestProfileView(@NonNull Context context, @
private void initializeResources() {
long oldThreadId = threadId;

long lastSeen = this.getActivity().getIntent().getLongExtra(ConversationActivity.LAST_SEEN_EXTRA, -1);
int startingPosition = this.getActivity().getIntent().getIntExtra(ConversationActivity.STARTING_POSITION_EXTRA, -1);
int startingPosition = this.getActivity().getIntent().getIntExtra(ConversationActivity.STARTING_POSITION_EXTRA, -1);

this.recipient = Recipient.live(getActivity().getIntent().getParcelableExtra(ConversationActivity.RECIPIENT_EXTRA));
this.threadId = this.getActivity().getIntent().getLongExtra(ConversationActivity.THREAD_ID_EXTRA, -1);
this.unknownSenderView = new UnknownSenderView(getActivity(), recipient.get(), threadId);

conversationViewModel.onConversationDataAvailable(threadId, lastSeen, startingPosition);
conversationViewModel.onConversationDataAvailable(threadId, startingPosition);

OnScrollListener scrollListener = new ConversationScrollListener(getActivity());
list.addOnScrollListener(scrollListener);
Expand Down Expand Up @@ -538,6 +537,7 @@ public void reload(Recipient recipient, long threadId) {
if (this.threadId != threadId) {
this.threadId = threadId;
messageRequestViewModel.setConversationInfo(recipient.getId(), threadId);
conversationViewModel.onConversationDataAvailable(threadId, -1);
initializeListAdapter();
}
}
Expand All @@ -551,8 +551,6 @@ public void scrollToBottom() {
}

public void setLastSeen(long lastSeen) {
conversationViewModel.onLastSeenChanged(lastSeen);

if (lastSeenDecoration != null) {
list.removeItemDecoration(lastSeenDecoration);
}
Expand Down Expand Up @@ -864,9 +862,7 @@ private void presentConversationMetadata(@NonNull ConversationData conversation)
adapter.setFooterView(null);
}

if (conversationViewModel.getLastSeen() == -1) {
setLastSeen(conversation.getLastSeen());
}
setLastSeen(conversation.getLastSeen());

if (FeatureFlags.messageRequests() && !conversation.hasPreMessageRequestMessages()) {
clearHeaderIfNotTyping(adapter);
Expand All @@ -880,34 +876,25 @@ private void presentConversationMetadata(@NonNull ConversationData conversation)

listener.onCursorChanged();

list.post(() -> {

int lastSeenPosition = adapter.findLastSeenPosition(conversationViewModel.getLastSeen());

if (isTypingIndicatorShowing()) {
lastSeenPosition = Math.max(lastSeenPosition - 1, 0);
}
int lastSeenPosition = adapter.getAdapterPositionForMessagePosition(conversation.getLastSeenPosition());

if (conversation.shouldJumpToMessage()) {
scrollToStartingPosition(conversation.getJumpToPosition());
} else if (conversation.isMessageRequestAccepted()) {
scrollToLastSeenPosition(lastSeenPosition);
}

if (lastSeenPosition <= 0) {
setLastSeen(0);
}
});
if (conversation.shouldJumpToMessage()) {
scrollToStartingPosition(conversation.getJumpToPosition());
} else if (conversation.isMessageRequestAccepted()) {
scrollToLastSeenPosition(lastSeenPosition);
} else if (FeatureFlags.messageRequests()) {
list.post(() -> getListLayoutManager().scrollToPosition(adapter.getItemCount() - 1));
}
}

private void scrollToStartingPosition(final int startingPosition) {
private void scrollToStartingPosition(int startingPosition) {
list.post(() -> {
list.getLayoutManager().scrollToPosition(startingPosition);
getListAdapter().pulseHighlightItem(startingPosition);
});
}

private void scrollToLastSeenPosition(final int lastSeenPosition) {
private void scrollToLastSeenPosition(int lastSeenPosition) {
if (lastSeenPosition > 0) {
list.post(() -> getListLayoutManager().scrollToPositionWithOffset(lastSeenPosition, list.getHeight()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,34 @@ class ConversationRepository {
this.executor = SignalExecutors.BOUNDED;
}

LiveData<ConversationData> getConversationData(long threadId, long lastSeen, int jumpToPosition) {
LiveData<ConversationData> getConversationData(long threadId, int jumpToPosition) {
MutableLiveData<ConversationData> liveData = new MutableLiveData<>();

executor.execute(() -> {
liveData.postValue(getConversationDataInternal(threadId, lastSeen, jumpToPosition));
liveData.postValue(getConversationDataInternal(threadId, jumpToPosition));
});

return liveData;
}

private @NonNull ConversationData getConversationDataInternal(long threadId, long lastSeen, int jumpToPosition) {
private @NonNull ConversationData getConversationDataInternal(long threadId, int jumpToPosition) {
Pair<Long, Boolean> lastSeenAndHasSent = DatabaseFactory.getThreadDatabase(context).getLastSeenAndHasSent(threadId);

boolean hasSent = lastSeenAndHasSent.second();

if (lastSeen == -1) {
lastSeen = lastSeenAndHasSent.first();
}
long lastSeen = lastSeenAndHasSent.first();
boolean hasSent = lastSeenAndHasSent.second();
int lastSeenPosition = 0;

boolean isMessageRequestAccepted = RecipientUtil.isMessageRequestAccepted(context, threadId);
boolean hasPreMessageRequestMessages = RecipientUtil.isPreMessageRequestThread(context, threadId);

return new ConversationData(lastSeen, hasSent, isMessageRequestAccepted, hasPreMessageRequestMessages, jumpToPosition);
if (lastSeen > 0) {
lastSeenPosition = DatabaseFactory.getMmsSmsDatabase(context).getMessagePositionForLastSeen(threadId, lastSeen);
}

if (lastSeenPosition <= 0) {
lastSeen = 0;
}

return new ConversationData(lastSeen, lastSeenPosition, hasSent, isMessageRequestAccepted, hasPreMessageRequestMessages, jumpToPosition);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ class ConversationViewModel extends ViewModel {
private final MutableLiveData<List<Media>> recentMedia;
private final MutableLiveData<Long> threadId;
private final LiveData<PagedList<MessageRecord>> messages;
private final LiveData<ConversationData> conversationMetadata;
private final LiveData<ConversationData> conversationMetadata;

private int jumpToPosition;
private long lastSeen;

private ConversationViewModel() {
this.context = ApplicationDependencies.getApplication();
Expand All @@ -56,7 +55,7 @@ private ConversationViewModel() {
});

conversationMetadata = Transformations.switchMap(threadId, thread -> {
LiveData<ConversationData> data = conversationRepository.getConversationData(thread, lastSeen, jumpToPosition);
LiveData<ConversationData> data = conversationRepository.getConversationData(thread, jumpToPosition);
jumpToPosition = -1;
return data;
});
Expand All @@ -66,17 +65,13 @@ void onAttachmentKeyboardOpen() {
mediaRepository.getMediaInBucket(context, Media.ALL_MEDIA_BUCKET_ID, recentMedia::postValue);
}

void onConversationDataAvailable(long threadId, long lastSeen, int startingPosition) {
this.lastSeen = lastSeen;
void onConversationDataAvailable(long threadId, int startingPosition) {
Log.d(TAG, "[onConversationDataAvailable] threadId: " + threadId + ", startingPosition: " + startingPosition);
this.jumpToPosition = startingPosition;

this.threadId.setValue(threadId);
}

void onLastSeenChanged(long lastSeen) {
this.lastSeen = lastSeen;
}

@NonNull LiveData<List<Media>> getRecentMedia() {
return recentMedia;
}
Expand All @@ -90,7 +85,11 @@ void onLastSeenChanged(long lastSeen) {
}

long getLastSeen() {
return lastSeen;
return conversationMetadata.getValue() != null ? conversationMetadata.getValue().getLastSeen() : 0;
}

int getLastSeenPosition() {
return conversationMetadata.getValue() != null ? conversationMetadata.getValue().getLastSeenPosition() : 0;
}

static class Factory extends ViewModelProvider.NewInstanceFactory {
Expand Down

0 comments on commit 53d122e

Please sign in to comment.