mirror of
				https://github.com/oxen-io/session-android.git
				synced 2025-10-25 01:11:17 +00:00 
			
		
		
		
	only load partial conversation by default
Closes #4252 Fixes #3911 // FREEBIE
This commit is contained in:
		 Jake McGinty
					Jake McGinty
				
			
				
					committed by
					
						 Moxie Marlinspike
						Moxie Marlinspike
					
				
			
			
				
	
			
			
			 Moxie Marlinspike
						Moxie Marlinspike
					
				
			
						parent
						
							4a3faf9086
						
					
				
				
					commit
					ae97495c47
				
			| @@ -20,17 +20,34 @@ import android.content.Context; | ||||
| import android.database.Cursor; | ||||
| import android.database.DataSetObserver; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.support.v7.widget.RecyclerView.ViewHolder; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
|  | ||||
| import org.thoughtcrime.securesms.util.VisibleForTesting; | ||||
|  | ||||
| /** | ||||
|  * RecyclerView.Adapter that manages a Cursor, comparable to the CursorAdapter usable in ListView/GridView. | ||||
|  */ | ||||
| public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> { | ||||
|   private final Context         context; | ||||
| public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<RecyclerView.ViewHolder> { | ||||
|   private final Context context; | ||||
|   private final DataSetObserver observer = new AdapterDataSetObserver(); | ||||
|  | ||||
|   private Cursor  cursor; | ||||
|   private boolean valid; | ||||
|   @VisibleForTesting final static int HEADER_TYPE = Integer.MIN_VALUE; | ||||
|   @VisibleForTesting final static int FOOTER_TYPE = Integer.MIN_VALUE + 1; | ||||
|  | ||||
|   private           Cursor  cursor; | ||||
|   private           boolean valid; | ||||
|   private @Nullable View    header; | ||||
|   private @Nullable View    footer; | ||||
|  | ||||
|   private static class HeaderFooterViewHolder extends RecyclerView.ViewHolder { | ||||
|     public HeaderFooterViewHolder(View itemView) { | ||||
|       super(itemView); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   protected CursorRecyclerViewAdapter(Context context, Cursor cursor) { | ||||
|     this.context = context; | ||||
| @@ -39,18 +56,32 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold | ||||
|       valid = true; | ||||
|       cursor.registerDataSetObserver(observer); | ||||
|     } | ||||
|  | ||||
|     setHasStableIds(false); | ||||
|   } | ||||
|  | ||||
|   public Context getContext() { | ||||
|   protected @NonNull Context getContext() { | ||||
|     return context; | ||||
|   } | ||||
|  | ||||
|   public Cursor getCursor() { | ||||
|   public @Nullable Cursor getCursor() { | ||||
|     return cursor; | ||||
|   } | ||||
|  | ||||
|   public void setHeaderView(@Nullable View header) { | ||||
|     this.header = header; | ||||
|   } | ||||
|  | ||||
|   public void setFooterView(@Nullable View footer) { | ||||
|     this.footer = footer; | ||||
|   } | ||||
|  | ||||
|   public boolean hasHeaderView() { | ||||
|     return header != null; | ||||
|   } | ||||
|  | ||||
|   public boolean hasFooterView() { | ||||
|     return footer != null; | ||||
|   } | ||||
|  | ||||
|   public void changeCursor(Cursor cursor) { | ||||
|     Cursor old = swapCursor(cursor); | ||||
|     if (old != null) { | ||||
| @@ -78,29 +109,50 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold | ||||
|     return oldCursor; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   @Override | ||||
|   public int getItemCount() { | ||||
|     return isActiveCursor() ? cursor.getCount() : 0; | ||||
|     if (!isActiveCursor()) return 0; | ||||
|  | ||||
|     return cursor.getCount() | ||||
|            + (hasHeaderView() ? 1 : 0) | ||||
|            + (hasFooterView() ? 1 : 0); | ||||
|   } | ||||
|  | ||||
|   @SuppressWarnings("unchecked") | ||||
|   @Override | ||||
|   public long getItemId(int position) { | ||||
|     return isActiveCursor() && cursor.moveToPosition(position) | ||||
|            ? cursor.getLong(cursor.getColumnIndexOrThrow("_id")) | ||||
|            : 0; | ||||
|   public final void onViewRecycled(ViewHolder holder) { | ||||
|     if (!(holder instanceof HeaderFooterViewHolder)) { | ||||
|       onItemViewRecycled((VH)holder); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public abstract void onBindViewHolder(VH viewHolder, @NonNull Cursor cursor); | ||||
|   public void onItemViewRecycled(VH holder) {} | ||||
|  | ||||
|   @Override public final ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|     switch (viewType) { | ||||
|     case HEADER_TYPE: return new HeaderFooterViewHolder(header); | ||||
|     case FOOTER_TYPE: return new HeaderFooterViewHolder(footer); | ||||
|     default:          return onCreateItemViewHolder(parent, viewType); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public abstract VH onCreateItemViewHolder(ViewGroup parent, int viewType); | ||||
|  | ||||
|   @SuppressWarnings("unchecked") | ||||
|   @Override | ||||
|   public void onBindViewHolder(VH viewHolder, int position) { | ||||
|     moveToPositionOrThrow(position); | ||||
|     onBindViewHolder(viewHolder, cursor); | ||||
|   public final void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { | ||||
|     if (!isHeaderPosition(position) && !isFooterPosition(position)) { | ||||
|       moveToPositionOrThrow(getCursorPosition(position)); | ||||
|       onBindItemViewHolder((VH)viewHolder, cursor); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public abstract void onBindItemViewHolder(VH viewHolder, @NonNull Cursor cursor); | ||||
|  | ||||
|   @Override public int getItemViewType(int position) { | ||||
|     moveToPositionOrThrow(position); | ||||
|     if (isHeaderPosition(position)) return HEADER_TYPE; | ||||
|     if (isFooterPosition(position)) return FOOTER_TYPE; | ||||
|     moveToPositionOrThrow(getCursorPosition(position)); | ||||
|     return getItemViewType(cursor); | ||||
|   } | ||||
|  | ||||
| @@ -125,6 +177,18 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold | ||||
|     return valid && cursor != null; | ||||
|   } | ||||
|  | ||||
|   private boolean isFooterPosition(int position) { | ||||
|     return hasFooterView() && position == getItemCount() - 1; | ||||
|   } | ||||
|  | ||||
|   private boolean isHeaderPosition(int position) { | ||||
|     return hasHeaderView() && position == 0; | ||||
|   } | ||||
|  | ||||
|   private int getCursorPosition(int position) { | ||||
|     return hasHeaderView() ? position - 1 : position; | ||||
|   } | ||||
|  | ||||
|   private class AdapterDataSetObserver extends DataSetObserver { | ||||
|     @Override | ||||
|     public void onChanged() { | ||||
|   | ||||
| @@ -42,7 +42,7 @@ public class MmsSmsDatabase extends Database { | ||||
|     super(context, databaseHelper); | ||||
|   } | ||||
|  | ||||
|   public Cursor getConversation(long threadId) { | ||||
|   public Cursor getConversation(long threadId, long limit) { | ||||
|     String[] projection    = {MmsSmsColumns.ID, SmsDatabase.BODY, SmsDatabase.TYPE, | ||||
|                               MmsSmsColumns.THREAD_ID, | ||||
|                               SmsDatabase.ADDRESS, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, | ||||
| @@ -60,12 +60,16 @@ public class MmsSmsDatabase extends Database { | ||||
|  | ||||
|     String selection       = MmsSmsColumns.THREAD_ID + " = " + threadId; | ||||
|  | ||||
|     Cursor cursor = queryTables(projection, selection, selection, order, null, null); | ||||
|     Cursor cursor = queryTables(projection, selection, selection, order, null, limit > 0 ? String.valueOf(limit) : null); | ||||
|     setNotifyConverationListeners(cursor, threadId); | ||||
|  | ||||
|     return cursor; | ||||
|   } | ||||
|  | ||||
|   public Cursor getConversation(long threadId) { | ||||
|     return getConversation(threadId, 0); | ||||
|   } | ||||
|  | ||||
|   public Cursor getIdentityConflictMessagesForThread(long threadId) { | ||||
|     String[] projection    = {MmsSmsColumns.ID, SmsDatabase.BODY, SmsDatabase.TYPE, | ||||
|                               MmsSmsColumns.THREAD_ID, | ||||
|   | ||||
| @@ -7,15 +7,21 @@ import org.thoughtcrime.securesms.database.DatabaseFactory; | ||||
| import org.thoughtcrime.securesms.util.AbstractCursorLoader; | ||||
|  | ||||
| public class ConversationLoader extends AbstractCursorLoader { | ||||
|   private final long                     threadId; | ||||
|   private final long threadId; | ||||
|   private       long limit; | ||||
|  | ||||
|   public ConversationLoader(Context context, long threadId) { | ||||
|   public ConversationLoader(Context context, long threadId, long limit) { | ||||
|     super(context); | ||||
|     this.threadId = threadId; | ||||
|     this.limit  = limit; | ||||
|   } | ||||
|  | ||||
|   public boolean hasLimit() { | ||||
|     return limit > 0; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public Cursor getCursor() { | ||||
|     return DatabaseFactory.getMmsSmsDatabase(context).getConversation(threadId); | ||||
|     return DatabaseFactory.getMmsSmsDatabase(context).getConversation(threadId, limit); | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user