refractoring (#4541)

This commit is contained in:
Aditya-Srivastav 2021-08-10 17:59:33 +05:30 committed by GitHub
parent a055f3baec
commit dfabaf8b42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 158 additions and 12 deletions

View file

@ -265,6 +265,9 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
}); });
} }
/**
* Launch Custom Selector.
*/
@OnClick(R.id.fab_custom_gallery) @OnClick(R.id.fab_custom_gallery)
void launchCustomSelector(){ void launchCustomSelector(){
controller.initiateCustomGalleryPickWithPermission(getActivity()); controller.initiateCustomGalleryPickWithPermission(getActivity());

View file

@ -6,7 +6,6 @@ import fr.free.nrw.commons.customselector.model.Image
/** /**
* Image Helper object, includes all the static functions required by custom selector. * Image Helper object, includes all the static functions required by custom selector.
*/ */
object ImageHelper { object ImageHelper {
/** /**
@ -65,10 +64,7 @@ object ImageHelper {
*/ */
fun getIndexList(list: ArrayList<Image>, masterList: ArrayList<Image>): ArrayList<Int> { fun getIndexList(list: ArrayList<Image>, masterList: ArrayList<Image>): ArrayList<Int> {
/** // Can be optimised as masterList is sorted by time.
* TODO
* Can be optimised as masterList is sorted by time.
*/
val indexes = arrayListOf<Int>() val indexes = arrayListOf<Int>()
for(image in list) { for(image in list) {

View file

@ -1,5 +1,15 @@
package fr.free.nrw.commons.customselector.listeners package fr.free.nrw.commons.customselector.listeners
/**
* Custom Selector Folder Click Listener
*/
interface FolderClickListener { interface FolderClickListener {
/**
* onFolderClick
* @param folderId : folder id of the folder.
* @param folderName : folder name of the folder.
* @param lastItemId : last scroll position in the folder.
*/
fun onFolderClick(folderId: Long, folderName: String, lastItemId: Long) fun onFolderClick(folderId: Long, folderName: String, lastItemId: Long)
} }

View file

@ -2,7 +2,21 @@ package fr.free.nrw.commons.customselector.listeners
import fr.free.nrw.commons.customselector.model.Image import fr.free.nrw.commons.customselector.model.Image
/**
* Custom Selector Image Loader Listener
* responds to the device image query.
*/
interface ImageLoaderListener { interface ImageLoaderListener {
/**
* On image loaded
* @param images : queried device images.
*/
fun onImageLoaded(images: ArrayList<Image>) fun onImageLoaded(images: ArrayList<Image>)
/**
* On failed
* @param throwable : throwable exception on failure.
*/
fun onFailed(throwable: Throwable) fun onFailed(throwable: Throwable)
} }

View file

@ -2,6 +2,14 @@ package fr.free.nrw.commons.customselector.listeners
import fr.free.nrw.commons.customselector.model.Image import fr.free.nrw.commons.customselector.model.Image
/**
* Custom selector Image select listener
*/
interface ImageSelectListener { interface ImageSelectListener {
/**
* onSelectedImagesChanged
* @param selectedImages : new selected images.
*/
fun onSelectedImagesChanged(selectedImages: ArrayList<Image>) fun onSelectedImagesChanged(selectedImages: ArrayList<Image>)
} }

View file

@ -1,5 +1,9 @@
package fr.free.nrw.commons.customselector.model package fr.free.nrw.commons.customselector.model
/**
* sealed class Callback Status.
* Current status of the device image query.
*/
sealed class CallbackStatus { sealed class CallbackStatus {
/** /**
IDLE : The callback is idle , doing nothing. IDLE : The callback is idle , doing nothing.

View file

@ -1,5 +1,8 @@
package fr.free.nrw.commons.customselector.model package fr.free.nrw.commons.customselector.model
/**
* Custom selector data class Folder.
*/
data class Folder( data class Folder(
/** /**
bucketId : Unique directory id, eg 540528482 bucketId : Unique directory id, eg 540528482

View file

@ -4,6 +4,9 @@ import android.net.Uri
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
/**
* Custom selector data class Image.
*/
data class Image( data class Image(
/** /**
id : Unique image id, primary key of image in device, eg 104950 id : Unique image id, primary key of image in device, eg 104950

View file

@ -1,5 +1,8 @@
package fr.free.nrw.commons.customselector.model package fr.free.nrw.commons.customselector.model
/**
* Custom selector data class Result.
*/
data class Result( data class Result(
/** /**
* CallbackStatus : stores the result status * CallbackStatus : stores the result status

View file

@ -13,6 +13,9 @@ import fr.free.nrw.commons.customselector.listeners.FolderClickListener
import fr.free.nrw.commons.customselector.model.Folder import fr.free.nrw.commons.customselector.model.Folder
import fr.free.nrw.commons.customselector.model.Image import fr.free.nrw.commons.customselector.model.Image
/**
* Custom selector FolderAdapter.
*/
class FolderAdapter( class FolderAdapter(
/** /**
* Application context. * Application context.
@ -91,7 +94,6 @@ class FolderAdapter(
diffResult.dispatchUpdatesTo(this) diffResult.dispatchUpdatesTo(this)
} }
/** /**
* returns item count. * returns item count.
*/ */

View file

@ -16,6 +16,9 @@ import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
import fr.free.nrw.commons.customselector.model.Image import fr.free.nrw.commons.customselector.model.Image
import fr.free.nrw.commons.customselector.ui.selector.ImageLoader import fr.free.nrw.commons.customselector.ui.selector.ImageLoader
/**
* Custom selector ImageAdapter.
*/
class ImageAdapter( class ImageAdapter(
/** /**
* Application Context. * Application Context.

View file

@ -16,6 +16,9 @@ import fr.free.nrw.commons.theme.BaseActivity
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
/**
* Custom Selector Activity.
*/
class CustomSelectorActivity: BaseActivity(), FolderClickListener, ImageSelectListener { class CustomSelectorActivity: BaseActivity(), FolderClickListener, ImageSelectListener {
/** /**

View file

@ -11,6 +11,9 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
/**
* Custom Selector view model.
*/
class CustomSelectorViewModel(var context: Context,var imageFileLoader: ImageFileLoader) : ViewModel() { class CustomSelectorViewModel(var context: Context,var imageFileLoader: ImageFileLoader) : ViewModel() {
/** /**

View file

@ -22,6 +22,9 @@ import fr.free.nrw.commons.upload.FileProcessor
import kotlinx.android.synthetic.main.fragment_custom_selector.view.* import kotlinx.android.synthetic.main.fragment_custom_selector.view.*
import javax.inject.Inject import javax.inject.Inject
/**
* Custom selector folder fragment.
*/
class FolderFragment : CommonsDaggerSupportFragment() { class FolderFragment : CommonsDaggerSupportFragment() {
/** /**

View file

@ -9,6 +9,10 @@ import kotlinx.coroutines.*
import java.io.File import java.io.File
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
/**
* Custom Selector Image File Loader.
* Loads device images.
*/
class ImageFileLoader(val context: Context) : CoroutineScope{ class ImageFileLoader(val context: Context) : CoroutineScope{
/** /**
@ -39,7 +43,7 @@ class ImageFileLoader(val context: Context) : CoroutineScope{
/** /**
* Load the device images using cursor * Load Device images using cursor
*/ */
private fun getImages(listener:ImageLoaderListener) { private fun getImages(listener:ImageLoaderListener) {
val cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, MediaStore.Images.Media.DATE_ADDED + " DESC") val cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, MediaStore.Images.Media.DATE_ADDED + " DESC")
@ -99,7 +103,7 @@ class ImageFileLoader(val context: Context) : CoroutineScope{
//todo Abort loading images. //todo Abort loading images.
} }
/** /*
* *
* TODO * TODO
* Sha1 for image (original image). * Sha1 for image (original image).

View file

@ -13,7 +13,7 @@ import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao;
public class DBOpenHelper extends SQLiteOpenHelper { public class DBOpenHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "commons.db"; private static final String DATABASE_NAME = "commons.db";
private static final int DATABASE_VERSION = 14; private static final int DATABASE_VERSION = 16;
public static final String CONTRIBUTIONS_TABLE = "contributions"; public static final String CONTRIBUTIONS_TABLE = "contributions";
private final String DROP_TABLE_STATEMENT="DROP TABLE IF EXISTS %s"; private final String DROP_TABLE_STATEMENT="DROP TABLE IF EXISTS %s";

View file

@ -68,6 +68,11 @@ public class CommonsApplicationModule {
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
} }
/**
* Provides ImageFileLoader used to fetch device images.
* @param context
* @return
*/
@Provides @Provides
public ImageFileLoader providesImageFileLoader(Context context) { public ImageFileLoader providesImageFileLoader(Context context) {
return new ImageFileLoader(context); return new ImageFileLoader(context);

View file

@ -53,6 +53,12 @@ public class FilePicker implements Constants {
.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, configuration(context).allowsMultiplePickingInGallery()); .putExtra(Intent.EXTRA_ALLOW_MULTIPLE, configuration(context).allowsMultiplePickingInGallery());
} }
/**
* CreateCustomSectorIntent, creates intent for custom selector activity.
* @param context
* @param type
* @return Custom selector intent
*/
private static Intent createCustomSelectorIntent(@NonNull Context context, int type) { private static Intent createCustomSelectorIntent(@NonNull Context context, int type) {
storeType(context, type); storeType(context, type);
return new Intent(context, CustomSelectorActivity.class); return new Intent(context, CustomSelectorActivity.class);
@ -215,6 +221,10 @@ public class FilePicker implements Constants {
} }
} }
/**
* onPictureReturnedFromCustomSelector.
* Retrieve and forward the images to upload wizard through callback.
*/
private static void onPictureReturnedFromCustomSelector(Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) { private static void onPictureReturnedFromCustomSelector(Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
try { try {
List<UploadableFile> files = getFilesFromCustomSelector(data, activity); List<UploadableFile> files = getFilesFromCustomSelector(data, activity);
@ -225,6 +235,10 @@ public class FilePicker implements Constants {
} }
} }
/**
* Get files from custom selector
* Retrieve and process the selected images from the custom selector.
*/
private static List<UploadableFile> getFilesFromCustomSelector(Intent data, Activity activity) throws IOException, SecurityException { private static List<UploadableFile> getFilesFromCustomSelector(Intent data, Activity activity) throws IOException, SecurityException {
List<UploadableFile> files = new ArrayList<>(); List<UploadableFile> files = new ArrayList<>();
ArrayList<Image> images = data.getParcelableArrayListExtra("Images"); ArrayList<Image> images = data.getParcelableArrayListExtra("Images");

View file

@ -24,19 +24,38 @@ import java.util.UUID;
import timber.log.Timber; import timber.log.Timber;
/**
* PickedFiles.
* Process the upload items.
*/
public class PickedFiles implements Constants { public class PickedFiles implements Constants {
/**
* Get Folder Name
* @param context
* @return default application folder name.
*/
private static String getFolderName(@NonNull Context context) { private static String getFolderName(@NonNull Context context) {
return FilePicker.configuration(context).getFolderName(); return FilePicker.configuration(context).getFolderName();
} }
/**
* tempImageDirectory
* @param context
* @return temporary image directory to copy and perform exif changes.
*/
private static File tempImageDirectory(@NonNull Context context) { private static File tempImageDirectory(@NonNull Context context) {
File privateTempDir = new File(context.getCacheDir(), DEFAULT_FOLDER_NAME); File privateTempDir = new File(context.getCacheDir(), DEFAULT_FOLDER_NAME);
if (!privateTempDir.exists()) privateTempDir.mkdirs(); if (!privateTempDir.exists()) privateTempDir.mkdirs();
return privateTempDir; return privateTempDir;
} }
/**
* writeToFile
* writes inputStream data to the destination file.
* @param in input stream of source file.
* @param file destination file
*/
private static void writeToFile(InputStream in, File file) { private static void writeToFile(InputStream in, File file) {
try { try {
OutputStream out = new FileOutputStream(file); OutputStream out = new FileOutputStream(file);
@ -52,11 +71,24 @@ public class PickedFiles implements Constants {
} }
} }
/**
* Copy file function.
* Copies source file to destination file.
* @param src source file
* @param dst destination file
* @throws IOException (File input stream exception)
*/
private static void copyFile(File src, File dst) throws IOException { private static void copyFile(File src, File dst) throws IOException {
InputStream in = new FileInputStream(src); InputStream in = new FileInputStream(src);
writeToFile(in, dst); writeToFile(in, dst);
} }
/**
* Copy files in separate thread.
* Copies all the uploadable files to the temp image folder on background thread.
* @param context
* @param filesToCopy uploadable file list to be copied.
*/
static void copyFilesInSeparateThread(final Context context, final List<UploadableFile> filesToCopy) { static void copyFilesInSeparateThread(final Context context, final List<UploadableFile> filesToCopy) {
new Thread(() -> { new Thread(() -> {
List<File> copiedFiles = new ArrayList<>(); List<File> copiedFiles = new ArrayList<>();
@ -64,7 +96,9 @@ public class PickedFiles implements Constants {
for (UploadableFile uploadableFile : filesToCopy) { for (UploadableFile uploadableFile : filesToCopy) {
File fileToCopy = uploadableFile.getFile(); File fileToCopy = uploadableFile.getFile();
File dstDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), getFolderName(context)); File dstDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), getFolderName(context));
if (!dstDir.exists()) dstDir.mkdirs(); if (!dstDir.exists()) {
dstDir.mkdirs();
}
String[] filenameSplit = fileToCopy.getName().split("\\."); String[] filenameSplit = fileToCopy.getName().split("\\.");
String extension = "." + filenameSplit[filenameSplit.length - 1]; String extension = "." + filenameSplit[filenameSplit.length - 1];
@ -84,12 +118,24 @@ public class PickedFiles implements Constants {
}).run(); }).run();
} }
/**
* singleFileList.
* converts a single uploadableFile to list of uploadableFile.
* @param file uploadable file
* @return
*/
static List<UploadableFile> singleFileList(UploadableFile file) { static List<UploadableFile> singleFileList(UploadableFile file) {
List<UploadableFile> list = new ArrayList<>(); List<UploadableFile> list = new ArrayList<>();
list.add(file); list.add(file);
return list; return list;
} }
/**
* ScanCopiedImages
* Scan copied images metadata using media scanner.
* @param context
* @param copiedImages copied images list.
*/
static void scanCopiedImages(Context context, List<File> copiedImages) { static void scanCopiedImages(Context context, List<File> copiedImages) {
String[] paths = new String[copiedImages.size()]; String[] paths = new String[copiedImages.size()];
for (int i = 0; i < copiedImages.size(); i++) { for (int i = 0; i < copiedImages.size(); i++) {
@ -104,6 +150,12 @@ public class PickedFiles implements Constants {
}); });
} }
/**
* pickedExistingPicture
* convert the image into uploadable file.
* @param photoUri Uri of the image.
* @return Uploadable file ready for tag redaction.
*/
public static UploadableFile pickedExistingPicture(@NonNull Context context, Uri photoUri) throws IOException, SecurityException {// SecurityException for those file providers who share URI but forget to grant necessary permissions public static UploadableFile pickedExistingPicture(@NonNull Context context, Uri photoUri) throws IOException, SecurityException {// SecurityException for those file providers who share URI but forget to grant necessary permissions
InputStream pictureInputStream = context.getContentResolver().openInputStream(photoUri); InputStream pictureInputStream = context.getContentResolver().openInputStream(photoUri);
File directory = tempImageDirectory(context); File directory = tempImageDirectory(context);
@ -116,6 +168,9 @@ public class PickedFiles implements Constants {
return new UploadableFile(photoUri, photoFile); return new UploadableFile(photoUri, photoFile);
} }
/**
* getCameraPictureLocation
*/
static File getCameraPicturesLocation(@NonNull Context context) throws IOException { static File getCameraPicturesLocation(@NonNull Context context) throws IOException {
File dir = tempImageDirectory(context); File dir = tempImageDirectory(context);
return File.createTempFile(UUID.randomUUID().toString(), ".jpg", dir); return File.createTempFile(UUID.randomUUID().toString(), ".jpg", dir);
@ -142,6 +197,11 @@ public class PickedFiles implements Constants {
return extension; return extension;
} }
/**
* GetUriToFile
* @param file get uri of file
* @return uri of requested file.
*/
static Uri getUriToFile(@NonNull Context context, @NonNull File file) { static Uri getUriToFile(@NonNull Context context, @NonNull File file) {
String packageName = context.getApplicationContext().getPackageName(); String packageName = context.getApplicationContext().getPackageName();
String authority = packageName + ".provider"; String authority = packageName + ".provider";

View file

@ -69,6 +69,11 @@ public class UploadItem {
return imageQuality.getValue(); return imageQuality.getValue();
} }
/**
* getContentUri.
* @return Uri of uploadItem
* Uri points to image location or name, eg content://media/external/images/camera/10495 (Android 10)
*/
public Uri getContentUri() { return contentUri; } public Uri getContentUri() { return contentUri; }
public void setImageQuality(final int imageQuality) { public void setImageQuality(final int imageQuality) {