mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-09 05:18:34 +00:00
Add placeholder support for ConversationListAdapter.
This commit is contained in:
parent
49f75d7036
commit
cf98a22269
@ -65,10 +65,6 @@ class ConversationDataSource extends PositionalDataSource<MessageRecord> {
|
|||||||
int totalCount = db.getConversationCount(threadId);
|
int totalCount = db.getConversationCount(threadId);
|
||||||
int effectiveCount = params.requestedStartPosition;
|
int effectiveCount = params.requestedStartPosition;
|
||||||
|
|
||||||
if (totalCount == 0 || params.requestedStartPosition > totalCount) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
try (MmsSmsDatabase.Reader reader = db.readerFor(db.getConversation(threadId, params.requestedStartPosition, params.requestedLoadSize))) {
|
try (MmsSmsDatabase.Reader reader = db.readerFor(db.getConversation(threadId, params.requestedStartPosition, params.requestedLoadSize))) {
|
||||||
MessageRecord record;
|
MessageRecord record;
|
||||||
while ((record = reader.getNext()) != null && effectiveCount < totalCount && !isInvalid()) {
|
while ((record = reader.getNext()) != null && effectiveCount < totalCount && !isInvalid()) {
|
||||||
@ -83,7 +79,7 @@ class ConversationDataSource extends PositionalDataSource<MessageRecord> {
|
|||||||
callback.onResult(result.getItems(), params.requestedStartPosition, result.getTotal());
|
callback.onResult(result.getItems(), params.requestedStartPosition, result.getTotal());
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.d(TAG, "[Initial Load] " + (System.currentTimeMillis() - start) + " ms" + (isInvalid() ? " -- invalidated" : ""));
|
Log.d(TAG, "[Initial Load] " + (System.currentTimeMillis() - start) + " ms | thread: " + threadId + ", start: " + params.requestedStartPosition + ", size: " + params.requestedLoadSize + (isInvalid() ? " -- invalidated" : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -102,7 +98,7 @@ class ConversationDataSource extends PositionalDataSource<MessageRecord> {
|
|||||||
|
|
||||||
callback.onResult(records);
|
callback.onResult(records);
|
||||||
|
|
||||||
Log.d(TAG, "[Update] " + (System.currentTimeMillis() - start) + " ms" + (isInvalid() ? " -- invalidated" : ""));
|
Log.d(TAG, "[Update] " + (System.currentTimeMillis() - start) + " ms | thread: " + threadId + ", start: " + params.startPosition + ", size: " + params.loadSize + (isInvalid() ? " -- invalidated" : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Factory extends DataSource.Factory<Integer, MessageRecord> {
|
static class Factory extends DataSource.Factory<Integer, MessageRecord> {
|
||||||
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.conversationlist;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.paging.PagedListAdapter;
|
import androidx.paging.PagedListAdapter;
|
||||||
@ -16,7 +17,7 @@ import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
|||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.CachedInflater;
|
import org.thoughtcrime.securesms.util.CachedInflater;
|
||||||
import org.thoughtcrime.securesms.util.Stopwatch;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -28,7 +29,11 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
class ConversationPagedListAdapter extends PagedListAdapter<Conversation, ConversationPagedListAdapter.ConversationViewHolder> {
|
class ConversationListAdapter extends PagedListAdapter<Conversation, RecyclerView.ViewHolder> {
|
||||||
|
|
||||||
|
private static final int TYPE_THREAD = 1;
|
||||||
|
private static final int TYPE_ACTION = 2;
|
||||||
|
private static final int TYPE_PLACEHOLDER = 3;
|
||||||
|
|
||||||
private enum Payload {
|
private enum Payload {
|
||||||
TYPING_INDICATOR,
|
TYPING_INDICATOR,
|
||||||
@ -42,7 +47,7 @@ class ConversationPagedListAdapter extends PagedListAdapter<Conversation, Conver
|
|||||||
private final Set<Long> typingSet = new HashSet<>();
|
private final Set<Long> typingSet = new HashSet<>();
|
||||||
private int archived;
|
private int archived;
|
||||||
|
|
||||||
protected ConversationPagedListAdapter(@NonNull GlideRequests glideRequests, @NonNull OnConversationClickListener onConversationClickListener) {
|
protected ConversationListAdapter(@NonNull GlideRequests glideRequests, @NonNull OnConversationClickListener onConversationClickListener) {
|
||||||
super(new ConversationDiffCallback());
|
super(new ConversationDiffCallback());
|
||||||
|
|
||||||
this.glideRequests = glideRequests;
|
this.glideRequests = glideRequests;
|
||||||
@ -50,10 +55,10 @@ class ConversationPagedListAdapter extends PagedListAdapter<Conversation, Conver
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull ConversationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public @NonNull RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
if (viewType == R.layout.conversation_list_item_action) {
|
if (viewType == TYPE_ACTION) {
|
||||||
ConversationViewHolder holder = new ConversationViewHolder(LayoutInflater.from(parent.getContext())
|
ConversationViewHolder holder = new ConversationViewHolder(LayoutInflater.from(parent.getContext())
|
||||||
.inflate(viewType, parent, false));
|
.inflate(R.layout.conversation_list_item_action, parent, false));
|
||||||
|
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v -> {
|
||||||
int position = holder.getAdapterPosition();
|
int position = holder.getAdapterPosition();
|
||||||
@ -64,9 +69,9 @@ class ConversationPagedListAdapter extends PagedListAdapter<Conversation, Conver
|
|||||||
});
|
});
|
||||||
|
|
||||||
return holder;
|
return holder;
|
||||||
} else {
|
} else if (viewType == TYPE_THREAD) {
|
||||||
ConversationViewHolder holder = new ConversationViewHolder(CachedInflater.from(parent.getContext())
|
ConversationViewHolder holder = new ConversationViewHolder(CachedInflater.from(parent.getContext())
|
||||||
.inflate(viewType, parent, false));
|
.inflate(R.layout.conversation_list_item_view, parent, false));
|
||||||
|
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v -> {
|
||||||
int position = holder.getAdapterPosition();
|
int position = holder.getAdapterPosition();
|
||||||
@ -86,11 +91,17 @@ class ConversationPagedListAdapter extends PagedListAdapter<Conversation, Conver
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
return holder;
|
return holder;
|
||||||
|
} else if (viewType == TYPE_PLACEHOLDER) {
|
||||||
|
View v = new FrameLayout(parent.getContext());
|
||||||
|
v.setLayoutParams(new FrameLayout.LayoutParams(1, ViewUtil.dpToPx(100)));
|
||||||
|
return new PlaceholderViewHolder(v);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Unknown type! " + viewType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ConversationViewHolder holder, int position, @NonNull List<Object> payloads) {
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
|
||||||
if (payloads.isEmpty()) {
|
if (payloads.isEmpty()) {
|
||||||
onBindViewHolder(holder, position);
|
onBindViewHolder(holder, position);
|
||||||
} else {
|
} else {
|
||||||
@ -99,9 +110,9 @@ class ConversationPagedListAdapter extends PagedListAdapter<Conversation, Conver
|
|||||||
Payload payload = (Payload) payloadObject;
|
Payload payload = (Payload) payloadObject;
|
||||||
|
|
||||||
if (payload == Payload.SELECTION) {
|
if (payload == Payload.SELECTION) {
|
||||||
holder.getConversationListItem().setBatchMode(batchMode);
|
((ConversationViewHolder) holder).getConversationListItem().setBatchMode(batchMode);
|
||||||
} else {
|
} else {
|
||||||
holder.getConversationListItem().updateTypingIndicator(typingSet);
|
((ConversationViewHolder) holder).getConversationListItem().updateTypingIndicator(typingSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,9 +120,11 @@ class ConversationPagedListAdapter extends PagedListAdapter<Conversation, Conver
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ConversationViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
||||||
if (holder.getItemViewType() == R.layout.conversation_list_item_action) {
|
if (holder.getItemViewType() == TYPE_ACTION) {
|
||||||
holder.getConversationListItem().bind(new ThreadRecord.Builder(100)
|
ConversationViewHolder casted = (ConversationViewHolder) holder;
|
||||||
|
|
||||||
|
casted.getConversationListItem().bind(new ThreadRecord.Builder(100)
|
||||||
.setBody("")
|
.setBody("")
|
||||||
.setDate(100)
|
.setDate(100)
|
||||||
.setRecipient(Recipient.UNKNOWN)
|
.setRecipient(Recipient.UNKNOWN)
|
||||||
@ -122,10 +135,11 @@ class ConversationPagedListAdapter extends PagedListAdapter<Conversation, Conver
|
|||||||
typingSet,
|
typingSet,
|
||||||
getBatchSelectionIds(),
|
getBatchSelectionIds(),
|
||||||
batchMode);
|
batchMode);
|
||||||
} else {
|
} else if (holder.getItemViewType() == TYPE_THREAD) {
|
||||||
Conversation conversation = Objects.requireNonNull(getItem(position));
|
ConversationViewHolder casted = (ConversationViewHolder) holder;
|
||||||
|
Conversation conversation = Objects.requireNonNull(getItem(position));
|
||||||
|
|
||||||
holder.getConversationListItem().bind(conversation.getThreadRecord(),
|
casted.getConversationListItem().bind(conversation.getThreadRecord(),
|
||||||
glideRequests,
|
glideRequests,
|
||||||
conversation.getLocale(),
|
conversation.getLocale(),
|
||||||
typingSet,
|
typingSet,
|
||||||
@ -135,8 +149,10 @@ class ConversationPagedListAdapter extends PagedListAdapter<Conversation, Conver
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewRecycled(@NonNull ConversationViewHolder holder) {
|
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
|
||||||
holder.getConversationListItem().unbind();
|
if (holder instanceof ConversationViewHolder) {
|
||||||
|
((ConversationViewHolder) holder).getConversationListItem().unbind();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTypingThreads(@NonNull Set<Long> typingThreadSet) {
|
void setTypingThreads(@NonNull Set<Long> typingThreadSet) {
|
||||||
@ -184,9 +200,11 @@ class ConversationPagedListAdapter extends PagedListAdapter<Conversation, Conver
|
|||||||
@Override
|
@Override
|
||||||
public int getItemViewType(int position) {
|
public int getItemViewType(int position) {
|
||||||
if (archived > 0 && position == getItemCount() - 1) {
|
if (archived > 0 && position == getItemCount() - 1) {
|
||||||
return R.layout.conversation_list_item_action;
|
return TYPE_ACTION;
|
||||||
|
} else if (getItem(position) == null) {
|
||||||
|
return TYPE_PLACEHOLDER;
|
||||||
} else {
|
} else {
|
||||||
return R.layout.conversation_list_item_view;
|
return TYPE_THREAD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,6 +262,12 @@ class ConversationPagedListAdapter extends PagedListAdapter<Conversation, Conver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class PlaceholderViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
PlaceholderViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface OnConversationClickListener {
|
interface OnConversationClickListener {
|
||||||
void onConversationClick(Conversation conversation);
|
void onConversationClick(Conversation conversation);
|
||||||
boolean onConversationLongClick(Conversation conversation);
|
boolean onConversationLongClick(Conversation conversation);
|
@ -137,7 +137,7 @@ import static android.app.Activity.RESULT_OK;
|
|||||||
|
|
||||||
|
|
||||||
public class ConversationListFragment extends MainFragment implements ActionMode.Callback,
|
public class ConversationListFragment extends MainFragment implements ActionMode.Callback,
|
||||||
ConversationPagedListAdapter.OnConversationClickListener,
|
ConversationListAdapter.OnConversationClickListener,
|
||||||
ConversationListSearchAdapter.EventListener,
|
ConversationListSearchAdapter.EventListener,
|
||||||
MainNavigator.BackHandler,
|
MainNavigator.BackHandler,
|
||||||
MegaphoneActionController
|
MegaphoneActionController
|
||||||
@ -167,7 +167,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||||||
private View toolbarShadow;
|
private View toolbarShadow;
|
||||||
private ConversationListViewModel viewModel;
|
private ConversationListViewModel viewModel;
|
||||||
private RecyclerView.Adapter activeAdapter;
|
private RecyclerView.Adapter activeAdapter;
|
||||||
private ConversationPagedListAdapter defaultAdapter;
|
private ConversationListAdapter defaultAdapter;
|
||||||
private ConversationListSearchAdapter searchAdapter;
|
private ConversationListSearchAdapter searchAdapter;
|
||||||
private StickyHeaderDecoration searchAdapterDecoration;
|
private StickyHeaderDecoration searchAdapterDecoration;
|
||||||
private ViewGroup megaphoneContainer;
|
private ViewGroup megaphoneContainer;
|
||||||
@ -465,7 +465,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeListAdapters() {
|
private void initializeListAdapters() {
|
||||||
defaultAdapter = new ConversationPagedListAdapter(GlideApp.with(this), this);
|
defaultAdapter = new ConversationListAdapter(GlideApp.with(this), this);
|
||||||
searchAdapter = new ConversationListSearchAdapter(GlideApp.with(this), this, Locale.getDefault());
|
searchAdapter = new ConversationListSearchAdapter(GlideApp.with(this), this, Locale.getDefault());
|
||||||
searchAdapterDecoration = new StickyHeaderDecoration(searchAdapter, false, false);
|
searchAdapterDecoration = new StickyHeaderDecoration(searchAdapter, false, false);
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ class ConversationListViewModel extends ViewModel {
|
|||||||
PagedList.Config config = new PagedList.Config.Builder()
|
PagedList.Config config = new PagedList.Config.Builder()
|
||||||
.setPageSize(15)
|
.setPageSize(15)
|
||||||
.setInitialLoadSizeHint(30)
|
.setInitialLoadSizeHint(30)
|
||||||
.setEnablePlaceholders(false)
|
.setEnablePlaceholders(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
this.conversationList = new LivePagedListBuilder<>(factory, config).setFetchExecutor(ConversationListDataSource.EXECUTOR)
|
this.conversationList = new LivePagedListBuilder<>(factory, config).setFetchExecutor(ConversationListDataSource.EXECUTOR)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user