Skip to content
This repository has been archived by the owner on Mar 30, 2024. It is now read-only.

Commit

Permalink
feat: paging support for dirs
Browse files Browse the repository at this point in the history
  • Loading branch information
jaiselrahman committed May 18, 2020
1 parent 5528fe1 commit 9e5d1d5
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 198 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,50 +37,38 @@
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.paging.PagedList;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.jaiselrahman.filepicker.R;
import com.jaiselrahman.filepicker.adapter.DirListAdapter;
import com.jaiselrahman.filepicker.config.Configurations;
import com.jaiselrahman.filepicker.loader.FileLoader;
import com.jaiselrahman.filepicker.loader.dir.DirLoader;
import com.jaiselrahman.filepicker.loader.dir.DirResultCallback;
import com.jaiselrahman.filepicker.model.FileLoader;
import com.jaiselrahman.filepicker.model.Dir;
import com.jaiselrahman.filepicker.model.DirViewModel;
import com.jaiselrahman.filepicker.model.MediaFile;
import com.jaiselrahman.filepicker.view.DividerItemDecoration;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class DirSelectActivity extends AppCompatActivity implements DirListAdapter.OnCameraClickListener {

public static final String MEDIA_FILES = "MEDIA_FILES";
public static final String CONFIGS = "CONFIGS";

private static final int REQUEST_WRITE_PERMISSION = 1;
private static final int REQUEST_CAMERA_PERMISSION_FOR_CAMERA = 2;
private static final int REQUEST_CAMERA_PERMISSION_FOR_VIDEO = 3;
private static final int REQUEST_DOCUMENT = 4;
private static final int REQUEST_FILE = 5;
private static final int INIT_SIZE = 6;

private Configurations configs;
private ArrayList<Dir> dirs = new ArrayList<>();
private DirListAdapter dirAdapter;

private DirResultCallback dirResultCallback = new DirResultCallback() {
@Override
public void onResult(final List<Dir> dirsResult) {
if (dirs != null) {
if (dirsResult.size() <= INIT_SIZE) {
dirAdapter.submitList(dirsResult);
} else {
dirAdapter.submitList(dirsResult.subList(0, INIT_SIZE));
dirAdapter.submitList(dirsResult);
}
}
}
};
private DirViewModel viewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
Expand Down Expand Up @@ -162,7 +150,7 @@ public boolean isAutoMeasureEnabled() {
recyclerView.setItemViewCacheSize(20);

if (requestPermission(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_WRITE_PERMISSION)) {
loadDirs(false);
loadDirs();
}
}

Expand All @@ -172,15 +160,23 @@ private boolean useDocumentUi() {
&& !(configs.isShowImages() || configs.isShowVideos() || configs.isShowAudios());
}

private void loadDirs(boolean restart) {
DirLoader.loadDirs(this, dirResultCallback, configs, restart);
private void loadDirs() {
viewModel = new ViewModelProvider(this, new DirViewModel.Factory(getContentResolver(), configs))
.get(DirViewModel.class);

viewModel.dirs.observe(this, new Observer<PagedList<Dir>>() {
@Override
public void onChanged(PagedList<Dir> dirs) {
dirAdapter.submitList(dirs);
}
});
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_WRITE_PERMISSION) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
loadDirs(false);
loadDirs();
} else {
Toast.makeText(this, R.string.permission_not_given, Toast.LENGTH_SHORT).show();
finish();
Expand Down Expand Up @@ -210,7 +206,7 @@ public void onScanCompleted(String path, final Uri uri) {
runOnUiThread(new Runnable() {
@Override
public void run() {
loadDirs(true);
viewModel.refresh();
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.MimeTypeMap;
Expand All @@ -49,7 +48,7 @@
import com.jaiselrahman.filepicker.adapter.FileGalleryAdapter.OnCameraClickListener;
import com.jaiselrahman.filepicker.adapter.MultiSelectionAdapter.OnSelectionListener;
import com.jaiselrahman.filepicker.config.Configurations;
import com.jaiselrahman.filepicker.loader.FileLoader;
import com.jaiselrahman.filepicker.model.FileLoader;
import com.jaiselrahman.filepicker.model.MediaFile;
import com.jaiselrahman.filepicker.model.MediaFileViewModel;
import com.jaiselrahman.filepicker.view.DividerItemDecoration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.paging.AsyncPagedListDiffer;
import androidx.paging.PagedList;
import androidx.recyclerview.widget.AsyncDifferConfig;
import androidx.recyclerview.widget.AsyncListDiffer;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListUpdateCallback;
import androidx.recyclerview.widget.RecyclerView;
Expand All @@ -46,7 +47,6 @@
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import static android.os.Environment.DIRECTORY_MOVIES;
Expand All @@ -67,7 +67,7 @@ public class DirListAdapter extends RecyclerView.Adapter<DirListAdapter.ViewHold
private int itemStartPosition;
private SimpleDateFormat TimeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault());

private AsyncListDiffer<Dir> differ = new AsyncListDiffer<>(this, new AsyncDifferConfig.Builder<>(DIR_ITEM_CALLBACK).build());
private AsyncPagedListDiffer<Dir> differ = new AsyncPagedListDiffer<>(this, new AsyncDifferConfig.Builder<>(DIR_ITEM_CALLBACK).build());

public DirListAdapter(Activity activity, int imageSize, boolean showCamera, boolean showVideoCamera) {
this.activity = activity;
Expand Down Expand Up @@ -208,19 +208,19 @@ public void setOnCameraClickListener(OnCameraClickListener onCameraClickListener
}

private Dir getItem(int position) {
return differ.getCurrentList().get(position);
return differ.getItem(position);
}

@Override
public int getItemCount() {
if (showCamera) {
if (showVideoCamera)
return differ.getCurrentList().size() + 2;
return differ.getCurrentList().size() + 1;
return differ.getItemCount() + 2;
return differ.getItemCount() + 1;
} else if (showVideoCamera) {
return differ.getCurrentList().size() + 1;
return differ.getItemCount() + 1;
}
return differ.getCurrentList().size();
return differ.getItemCount();
}

@Override
Expand All @@ -243,7 +243,7 @@ public void onChanged(int position, int count, Object payload) {
notifyItemRangeChanged(itemStartPosition + position, count, payload);
}

public void submitList(List<Dir> dirs) {
public void submitList(PagedList<Dir> dirs) {
differ.submitList(dirs);
}

Expand Down Expand Up @@ -287,10 +287,10 @@ public boolean areItemsTheSame(@NonNull Dir oldItem, @NonNull Dir newItem) {

@Override
public boolean areContentsTheSame(@NonNull Dir oldItem, @NonNull Dir newItem) {
return oldItem.getName() != null && oldItem.getName().equals(newItem.getName())
return (oldItem.getName() != null && oldItem.getName().equals(newItem.getName()))
&& oldItem.getCount() == newItem.getCount()
&& (oldItem.getPreview() == null && newItem.getPreview() == null)
|| oldItem.getPreview().equals(newItem.getPreview());
&& ((oldItem.getPreview() == null && newItem.getPreview() == null)
|| (oldItem.getPreview() !=null && oldItem.getPreview().equals(newItem.getPreview())));
}
};
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@
* limitations under the License.
*/

package com.jaiselrahman.filepicker.loader.dir;
package com.jaiselrahman.filepicker.model;

import android.content.Context;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;

import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.CursorLoader;
import androidx.core.content.ContentResolverCompat;
import androidx.paging.DataSource;
import androidx.paging.PositionalDataSource;

import com.jaiselrahman.filepicker.config.Configurations;

Expand All @@ -40,29 +42,23 @@
import static android.provider.MediaStore.MediaColumns.DATA;
import static android.provider.MediaStore.MediaColumns.DATE_ADDED;
import static android.provider.MediaStore.MediaColumns.SIZE;
import static com.jaiselrahman.filepicker.loader.FileLoader.appendDefaultFileSelection;
import static com.jaiselrahman.filepicker.loader.FileLoader.appendFileSelection;

public class DirLoader extends CursorLoader {
static final String COUNT = "count";

private static final String[] DIR_PROJECTION = new String[]{
MediaStore.Files.FileColumns._ID,
MediaStore.Files.FileColumns.DATA,
MediaStore.Files.FileColumns.BUCKET_ID,
MediaStore.Files.FileColumns.BUCKET_DISPLAY_NAME,
MEDIA_TYPE,
};

static final int COLUMN_ID = 0;
static final int COLUMN_DATA = 1;
static final int COLUMN_BUCKET_ID = 2;
static final int COLUMN_BUCKET_DISPLAY_NAME = 3;
static final int COLUMN_MEDIA_TYPE = 4;
static final int COLUMN_COUNT = 5;

DirLoader(Context context, @NonNull Configurations configs) {
super(context);
import static com.jaiselrahman.filepicker.model.MediaFileDataSource.appendDefaultFileSelection;
import static com.jaiselrahman.filepicker.model.MediaFileDataSource.appendFileSelection;

public class DirDataSource extends PositionalDataSource<Dir> {
private Configurations configs;
private ContentResolver contentResolver;

private String[] projection;
private String sortOrder;
private String selection;
private String[] selectionArgs;
private Uri uri;

private DirDataSource(ContentResolver contentResolver, Uri uri, @NonNull Configurations configs) {
this.contentResolver = contentResolver;
this.configs = configs;
this.uri = uri;

ArrayList<String> selectionArgs = new ArrayList<>();
StringBuilder selectionBuilder = new StringBuilder(200);
Expand Down Expand Up @@ -118,37 +114,63 @@ public class DirLoader extends CursorLoader {
selectionBuilder.append(BUCKET_ID).append(" IS NOT NULL");
}

if (selectionBuilder.length() != 0) {
setProjection(getDirProjection());
setUri(MediaStore.Files.getContentUri("external"));
setSortOrder(DATE_ADDED + " DESC");
setSelection(selectionBuilder.toString());
setSelectionArgs(selectionArgs.toArray(new String[0]));
}
this.projection = getDirProjection();
this.sortOrder = DATE_ADDED + " DESC";
this.selection = selectionBuilder.toString();
this.selectionArgs = selectionArgs.toArray(new String[0]);
}

@Override
public void loadInitial(@NonNull LoadInitialParams params, @NonNull LoadInitialCallback<Dir> callback) {
callback.onResult(getDirs(params.requestedStartPosition, params.requestedLoadSize), 0);
}

@Override
public void loadRange(@NonNull LoadRangeParams params, @NonNull LoadRangeCallback<Dir> callback) {
callback.onResult(getDirs(params.startPosition, params.loadSize));
}

private List<Dir> getDirs(int offset, int limit) {
Cursor data = ContentResolverCompat.query(contentResolver, uri, projection,
selection, selectionArgs,
sortOrder + " LIMIT " + limit + " OFFSET " + offset, null);

return DirLoader.getDirs(data, configs);
}

private static String[] getDirProjection() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return DIR_PROJECTION;
return DirLoader.DIR_PROJECTION;
}

List<String> projection = new ArrayList<>();
Collections.addAll(projection, DIR_PROJECTION);
projection.add("COUNT(*) as " + COUNT);
Collections.addAll(projection, DirLoader.DIR_PROJECTION);
projection.add("COUNT(*) as " + DirLoader.COUNT);

return projection.toArray(new String[0]);
}

public static void loadDirs(FragmentActivity activity, DirResultCallback dirResultCallback, Configurations configs, boolean restart) {
if (configs.isShowFiles() || configs.isShowVideos() || configs.isShowAudios() || configs.isShowImages()) {
DirLoaderCallback dirLoaderCallBack = new DirLoaderCallback(activity, dirResultCallback, configs);
if (!restart) {
LoaderManager.getInstance(activity).initLoader(0, null, dirLoaderCallBack);
} else {
LoaderManager.getInstance(activity).restartLoader(0, null, dirLoaderCallBack);
}
} else {
dirResultCallback.onResult(null);
public static class Factory extends DataSource.Factory<Integer, Dir> {
private ContentResolver contentResolver;
private Configurations configs;

private Uri uri;

Factory(ContentResolver contentResolver, Configurations configs) {
this.contentResolver = contentResolver;
this.configs = configs;

uri = MediaStore.Files.getContentUri("external");
}

public Uri getUri() {
return uri;
}

@NonNull
@Override
public DataSource<Integer, Dir> create() {
return new DirDataSource(contentResolver, uri, configs);
}
}
}
Loading

0 comments on commit 9e5d1d5

Please sign in to comment.