diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8fc66230f..4fa7e4f82 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -46,7 +46,10 @@
android:finishOnTaskLaunch="true" />
+ android:name=".media.ZoomableActivity"
+ android:label="Zoomable Activity"
+ android:configChanges="screenSize|keyboard|orientation"
+ android:parentActivityName=".customselector.ui.selector.CustomSelectorActivity" />
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedDao.kt b/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedDao.kt
index 619504e7d..d8c100a08 100644
--- a/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedDao.kt
@@ -66,4 +66,18 @@ abstract class UploadedStatusDao {
suspend fun getUploadedFromImageSHA1(imageSHA1: String):UploadedStatus? {
return getFromImageSHA1(imageSHA1)
}
+
+ /**
+ * Check whether the imageSHA1 is present in database
+ */
+ @Query("SELECT COUNT() FROM uploaded_table WHERE imageSHA1 = (:imageSHA1) AND imageResult = (:imageResult) ")
+ abstract suspend fun findByImageSHA1(imageSHA1 : String, imageResult: Boolean): Int
+
+ /**
+ * Check whether the modifiedImageSHA1 is present in database
+ */
+ @Query("SELECT COUNT() FROM uploaded_table WHERE modifiedImageSHA1 = (:modifiedImageSHA1) AND modifiedImageResult = (:modifiedImageResult) ")
+ abstract suspend fun findByModifiedImageSHA1(modifiedImageSHA1 : String,
+ modifiedImageResult: Boolean): Int
+
}
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/helper/CustomSelectorConstants.kt b/app/src/main/java/fr/free/nrw/commons/customselector/helper/CustomSelectorConstants.kt
new file mode 100644
index 000000000..3f5b26c96
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/helper/CustomSelectorConstants.kt
@@ -0,0 +1,10 @@
+package fr.free.nrw.commons.customselector.helper
+
+object CustomSelectorConstants {
+
+ const val TOTAL_IMAGES = "total_images"
+ const val TOTAL_SELECTED_IMAGES = "total_selected_images"
+ const val PRESENT_POSITION = "present_position"
+ const val NEW_SELECTED_IMAGES = "new_selected_images"
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/helper/OnSwipeTouchListener.kt b/app/src/main/java/fr/free/nrw/commons/customselector/helper/OnSwipeTouchListener.kt
new file mode 100644
index 000000000..b39d976ee
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/helper/OnSwipeTouchListener.kt
@@ -0,0 +1,72 @@
+package fr.free.nrw.commons.customselector.helper
+
+import android.content.Context
+import android.view.GestureDetector
+import android.view.MotionEvent
+import android.view.View
+import kotlin.math.abs
+
+/**
+ * Class for detecting swipe gestures
+ */
+open class OnSwipeTouchListener(context: Context?) : View.OnTouchListener {
+
+ private val gestureDetector: GestureDetector
+
+ override fun onTouch(view: View?, motionEvent: MotionEvent?): Boolean {
+ return gestureDetector.onTouchEvent(motionEvent)
+ }
+
+ private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
+
+ private val SWIPE_THRESHOLD = 100
+ private val SWIPE_VELOCITY_THRESHOLD = 100
+
+ override fun onDown(e: MotionEvent?): Boolean {
+ return true
+ }
+
+ override fun onFling(
+ event1: MotionEvent,
+ event2: MotionEvent,
+ velocityX: Float,
+ velocityY: Float
+ ): Boolean {
+ try {
+ val diffY: Float = event2.y - event1.y
+ val diffX: Float = event2.x - event1.x
+ if (abs(diffX) > abs(diffY)) {
+ if (abs(diffX) > SWIPE_THRESHOLD && abs(velocityX) >
+ SWIPE_VELOCITY_THRESHOLD) {
+ if (diffX > 0) {
+ onSwipeRight()
+ } else {
+ onSwipeLeft()
+ }
+ }
+ } else {
+ if (abs(diffY) > SWIPE_THRESHOLD && abs(velocityY) >
+ SWIPE_VELOCITY_THRESHOLD) {
+ if (diffY > 0) {
+ onSwipeDown()
+ } else {
+ onSwipeUp()
+ }
+ }
+ }
+ } catch (exception: Exception) {
+ exception.printStackTrace()
+ }
+ return false
+ }
+ }
+
+ open fun onSwipeRight() {}
+ open fun onSwipeLeft() {}
+ open fun onSwipeUp() {}
+ open fun onSwipeDown() {}
+
+ init {
+ gestureDetector = GestureDetector(context, GestureListener())
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/listeners/ImageSelectListener.kt b/app/src/main/java/fr/free/nrw/commons/customselector/listeners/ImageSelectListener.kt
index a9cc85e19..d6349eb49 100644
--- a/app/src/main/java/fr/free/nrw/commons/customselector/listeners/ImageSelectListener.kt
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/listeners/ImageSelectListener.kt
@@ -19,5 +19,9 @@ interface ImageSelectListener {
* onLongPress
* @param imageUri : uri of image
*/
- fun onLongPress(imageUri: Uri)
+ fun onLongPress(
+ position: Int,
+ images: ArrayList,
+ selectedImages: ArrayList
+ )
}
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/listeners/PassDataListener.kt b/app/src/main/java/fr/free/nrw/commons/customselector/listeners/PassDataListener.kt
new file mode 100644
index 000000000..8d32d948d
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/listeners/PassDataListener.kt
@@ -0,0 +1,7 @@
+package fr.free.nrw.commons.customselector.listeners
+
+import fr.free.nrw.commons.customselector.model.Image
+
+interface PassDataListener {
+ fun passSelectedImages(selectedImages: ArrayList)
+}
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapter.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapter.kt
index 1e81c9466..d25e0fd1c 100644
--- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapter.kt
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapter.kt
@@ -228,7 +228,7 @@ class ImageAdapter(
// launch media preview on long click.
holder.itemView.setOnLongClickListener {
- imageSelectListener.onLongPress(image.uri)
+ imageSelectListener.onLongPress(position, images, selectedImages)
true
}
}
@@ -317,6 +317,13 @@ class ImageAdapter(
diffResult.dispatchUpdatesTo(this)
}
+ /**
+ * Set new selected images
+ */
+ fun setSelectedImages(newSelectedImages: ArrayList){
+ selectedImages = ArrayList(newSelectedImages)
+ imageSelectListener.onSelectedImagesChanged(selectedImages, 0)
+ }
/**
* Refresh the data in the adapter
*/
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt
index 5de0aeca5..3d3ff55c9 100644
--- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt
@@ -4,7 +4,6 @@ import android.app.Activity
import android.app.Dialog
import android.content.Intent
import android.content.SharedPreferences
-import android.net.Uri
import android.os.Bundle
import android.view.View
import android.view.Window
@@ -16,6 +15,7 @@ import androidx.lifecycle.ViewModelProvider
import fr.free.nrw.commons.R
import fr.free.nrw.commons.customselector.database.NotForUploadStatus
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
+import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants
import fr.free.nrw.commons.customselector.listeners.FolderClickListener
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
import fr.free.nrw.commons.customselector.model.Image
@@ -112,6 +112,18 @@ class CustomSelectorActivity: BaseActivity(), FolderClickListener, ImageSelectLi
}
}
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ if (requestCode == 101) {
+ if (resultCode == Activity.RESULT_OK) {
+ val selectedImages: ArrayList =
+ data!!
+ .getParcelableArrayListExtra(CustomSelectorConstants.NEW_SELECTED_IMAGES)!!
+ imageFragment!!.passSelectedImages(selectedImages)
+ }
+ }
+ }
+
/**
* Show Custom Selector Welcome Dialog.
*/
@@ -305,9 +317,19 @@ class CustomSelectorActivity: BaseActivity(), FolderClickListener, ImageSelectLi
* onLongPress
* @param imageUri : uri of image
*/
- override fun onLongPress(imageUri: Uri) {
- val intent = Intent(this, ZoomableActivity::class.java).setData(imageUri);
- startActivity(intent)
+ override fun onLongPress(
+ position: Int,
+ images: ArrayList,
+ selectedImages: ArrayList
+ ) {
+ val intent = Intent(this, ZoomableActivity::class.java)
+ intent.putExtra(CustomSelectorConstants.PRESENT_POSITION, position);
+ intent.putParcelableArrayListExtra(CustomSelectorConstants.TOTAL_IMAGES, images)
+ intent.putParcelableArrayListExtra(
+ CustomSelectorConstants.TOTAL_SELECTED_IMAGES,
+ selectedImages
+ )
+ startActivityForResult(intent, 101)
}
/**
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt
index a6025e23d..b7da43a85 100644
--- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt
@@ -19,6 +19,7 @@ import fr.free.nrw.commons.R
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
import fr.free.nrw.commons.customselector.database.UploadedStatusDao
import fr.free.nrw.commons.customselector.helper.ImageHelper
+import fr.free.nrw.commons.customselector.listeners.PassDataListener
import fr.free.nrw.commons.customselector.helper.ImageHelper.CUSTOM_SELECTOR_PREFERENCE_KEY
import fr.free.nrw.commons.customselector.helper.ImageHelper.SWITCH_STATE_PREFERENCE_KEY
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
@@ -42,7 +43,7 @@ import kotlin.collections.ArrayList
/**
* Custom Selector Image Fragment.
*/
-class ImageFragment: CommonsDaggerSupportFragment(), RefreshUIListener {
+class ImageFragment: CommonsDaggerSupportFragment(), RefreshUIListener, PassDataListener {
/**
* Current bucketId.
@@ -293,6 +294,7 @@ class ImageFragment: CommonsDaggerSupportFragment(), RefreshUIListener {
* notifyDataSetChanged, rebuild the holder views to account for deleted images.
*/
override fun onResume() {
+ Log.d("haha", "onResume: ")
imageAdapter.notifyDataSetChanged()
super.onResume()
}
@@ -327,4 +329,8 @@ class ImageFragment: CommonsDaggerSupportFragment(), RefreshUIListener {
override fun refresh() {
imageAdapter.refresh(filteredImages, allImages)
}
+
+ override fun passSelectedImages(selectedImages: ArrayList){
+ imageAdapter.setSelectedImages(selectedImages)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java b/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java
index 31412236d..6a9277906 100644
--- a/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java
+++ b/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java
@@ -13,6 +13,7 @@ import fr.free.nrw.commons.customselector.ui.selector.CustomSelectorActivity;
import fr.free.nrw.commons.description.DescriptionEditActivity;
import fr.free.nrw.commons.explore.depictions.WikidataItemDetailsActivity;
import fr.free.nrw.commons.explore.SearchActivity;
+import fr.free.nrw.commons.media.ZoomableActivity;
import fr.free.nrw.commons.notification.NotificationActivity;
import fr.free.nrw.commons.profile.ProfileActivity;
import fr.free.nrw.commons.review.ReviewActivity;
@@ -75,4 +76,7 @@ public abstract class ActivityBuilderModule {
@ContributesAndroidInjector
abstract DescriptionEditActivity bindDescriptionEditActivity();
+
+ @ContributesAndroidInjector
+ abstract ZoomableActivity bindZoomableActivity();
}
diff --git a/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.java b/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.java
deleted file mode 100644
index 286384ff1..000000000
--- a/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package fr.free.nrw.commons.media;
-
-import android.graphics.drawable.Animatable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.ProgressBar;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
-import butterknife.BindView;
-import butterknife.ButterKnife;
-import com.facebook.drawee.backends.pipeline.Fresco;
-import com.facebook.drawee.controller.BaseControllerListener;
-import com.facebook.drawee.controller.ControllerListener;
-import com.facebook.drawee.drawable.ProgressBarDrawable;
-import com.facebook.drawee.drawable.ScalingUtils;
-import com.facebook.drawee.generic.GenericDraweeHierarchy;
-import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
-import com.facebook.drawee.interfaces.DraweeController;
-import com.facebook.imagepipeline.image.ImageInfo;
-import fr.free.nrw.commons.R;
-import fr.free.nrw.commons.media.zoomControllers.zoomable.DoubleTapGestureListener;
-import fr.free.nrw.commons.media.zoomControllers.zoomable.ZoomableDraweeView;
-import timber.log.Timber;
-
-
-public class ZoomableActivity extends AppCompatActivity {
- private Uri imageUri;
-
- @BindView(R.id.zoomable)
- ZoomableDraweeView photo;
- @BindView(R.id.zoom_progress_bar)
- ProgressBar spinner;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- imageUri = getIntent().getData();
- if (null == imageUri) {
- throw new IllegalArgumentException("No data to display");
- }
- Timber.d("URl = " + imageUri);
-
- setContentView(R.layout.activity_zoomable);
- ButterKnife.bind(this);
- init();
- }
-
- /**
- * Two types of loading indicators have been added to the zoom activity:
- * 1. An Indeterminate spinner for showing the time lapsed between dispatch of the image request
- * and starting to receiving the image.
- * 2. ProgressBarDrawable that reflects how much image has been downloaded
- */
- private final ControllerListener loadingListener = new BaseControllerListener() {
- @Override
- public void onSubmit(String id, Object callerContext) {
- // Sometimes the spinner doesn't appear when rapidly switching between images, this fixes that
- spinner.setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onIntermediateImageSet(String id, @Nullable ImageInfo imageInfo) {
- spinner.setVisibility(View.GONE);
- }
- @Override
- public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable animatable) {
- spinner.setVisibility(View.GONE);
- }
- };
- private void init() {
- if( imageUri != null ) {
- GenericDraweeHierarchy hierarchy = GenericDraweeHierarchyBuilder.newInstance(getResources())
- .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
- .setProgressBarImage(new ProgressBarDrawable())
- .setProgressBarImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
- .build();
- photo.setHierarchy(hierarchy);
- photo.setAllowTouchInterceptionWhileZoomed(true);
- photo.setIsLongpressEnabled(false);
- photo.setTapListener(new DoubleTapGestureListener(photo));
- DraweeController controller = Fresco.newDraweeControllerBuilder()
- .setUri(imageUri)
- .setControllerListener(loadingListener)
- .build();
- photo.setController(controller);
- }
- }
-
-
-}
diff --git a/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.kt b/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.kt
new file mode 100644
index 000000000..8d788dcc6
--- /dev/null
+++ b/app/src/main/java/fr/free/nrw/commons/media/ZoomableActivity.kt
@@ -0,0 +1,387 @@
+package fr.free.nrw.commons.media
+
+import android.app.Activity
+import android.content.Intent
+import android.graphics.drawable.Animatable
+import android.net.Uri
+import android.os.Bundle
+import android.view.View
+import android.widget.ProgressBar
+import android.widget.TextView
+import android.widget.Toast
+import butterknife.BindView
+import butterknife.ButterKnife
+import com.facebook.drawee.backends.pipeline.Fresco
+import com.facebook.drawee.controller.BaseControllerListener
+import com.facebook.drawee.controller.ControllerListener
+import com.facebook.drawee.drawable.ProgressBarDrawable
+import com.facebook.drawee.drawable.ScalingUtils
+import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
+import com.facebook.drawee.interfaces.DraweeController
+import com.facebook.imagepipeline.image.ImageInfo
+import fr.free.nrw.commons.R
+import fr.free.nrw.commons.customselector.database.NotForUploadStatus
+import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
+import fr.free.nrw.commons.customselector.database.UploadedStatusDao
+import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants
+import fr.free.nrw.commons.customselector.helper.OnSwipeTouchListener
+import fr.free.nrw.commons.customselector.model.Image
+import fr.free.nrw.commons.media.zoomControllers.zoomable.DoubleTapGestureListener
+import fr.free.nrw.commons.media.zoomControllers.zoomable.ZoomableDraweeView
+import fr.free.nrw.commons.theme.BaseActivity
+import fr.free.nrw.commons.upload.FileProcessor
+import fr.free.nrw.commons.upload.FileUtilsWrapper
+import fr.free.nrw.commons.utils.CustomSelectorUtils
+import kotlinx.coroutines.*
+import timber.log.Timber
+import javax.inject.Inject
+
+class ZoomableActivity : BaseActivity() {
+
+ private lateinit var imageUri: Uri
+
+ @JvmField
+ @BindView(R.id.zoomable)
+ var photo: ZoomableDraweeView? = null
+
+ @JvmField
+ @BindView(R.id.zoom_progress_bar)
+ var spinner: ProgressBar? = null
+
+ @JvmField
+ @BindView(R.id.selection_count)
+ var selectedCount: TextView? = null
+
+ /**
+ * Total images present in folder
+ */
+ private var images: ArrayList? = null
+
+ /**
+ * Total selected images present in folder
+ */
+ private var selectedImages: ArrayList? = null
+
+ /**
+ * Present position of the image
+ */
+ private var position = 0
+
+ /**
+ * FileUtilsWrapper class to get imageSHA1 from uri
+ */
+ @Inject
+ lateinit var fileUtilsWrapper: FileUtilsWrapper
+
+ /**
+ * FileProcessor to pre-process the file.
+ */
+ @Inject
+ lateinit var fileProcessor: FileProcessor
+
+ /**
+ * NotForUploadStatus Dao class for database operations
+ */
+ @Inject
+ lateinit var notForUploadStatusDao: NotForUploadStatusDao
+
+ /**
+ * UploadedStatus Dao class for database operations
+ */
+ @Inject
+ lateinit var uploadedStatusDao: UploadedStatusDao
+
+ /**
+ * Coroutine Dispatchers and Scope.
+ */
+ private var defaultDispatcher : CoroutineDispatcher = Dispatchers.Default
+ private var ioDispatcher : CoroutineDispatcher = Dispatchers.IO
+ private val scope : CoroutineScope = MainScope()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ images = intent.getParcelableArrayListExtra(
+ CustomSelectorConstants.TOTAL_IMAGES
+ )
+ selectedImages = intent.getParcelableArrayListExtra(
+ CustomSelectorConstants.TOTAL_SELECTED_IMAGES
+ )
+ position = intent.getIntExtra(CustomSelectorConstants.PRESENT_POSITION, 0)
+ imageUri = if (images.isNullOrEmpty()) {
+ intent.data as Uri
+ } else {
+ images!![position].uri
+ }
+ Timber.d("URl = $imageUri")
+ setContentView(R.layout.activity_zoomable)
+ ButterKnife.bind(this)
+ init(imageUri)
+ onSwap()
+ }
+
+ /**
+ * Handle swap gestures. Ex. onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeDown
+ */
+ private fun onSwap() {
+ if (!images.isNullOrEmpty()) {
+ photo!!.setOnTouchListener(object : OnSwipeTouchListener(this) {
+ override fun onSwipeLeft() {
+ super.onSwipeLeft()
+ if (position < images!!.size - 1) {
+ position++
+ init(images!![position].uri)
+ } else {
+ Toast.makeText(
+ this@ZoomableActivity,
+ "No more images found",
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+
+ override fun onSwipeRight() {
+ super.onSwipeRight()
+ if (position > 0) {
+ position--
+ init(images!![position].uri)
+ } else {
+ Toast.makeText(
+ this@ZoomableActivity,
+ "No more images found",
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+
+ override fun onSwipeUp() {
+ super.onSwipeUp()
+ scope.launch {
+ val imageSHA1 = CustomSelectorUtils.getImageSHA1(
+ images!![position].uri,
+ ioDispatcher,
+ fileUtilsWrapper,
+ contentResolver
+ )
+ var isNonActionable = notForUploadStatusDao.find(imageSHA1)
+ if (isNonActionable > 0) {
+ Toast.makeText(
+ this@ZoomableActivity,
+ "Can't select this image for upload", Toast.LENGTH_SHORT
+ ).show()
+ } else {
+ isNonActionable =
+ uploadedStatusDao.findByImageSHA1(imageSHA1, true)
+ if (isNonActionable > 0) {
+ Toast.makeText(
+ this@ZoomableActivity,
+ "Can't select this image for upload", Toast.LENGTH_SHORT
+ ).show()
+ } else {
+ val imageModifiedSHA1 = CustomSelectorUtils.generateModifiedSHA1(
+ images!![position],
+ defaultDispatcher,
+ this@ZoomableActivity,
+ fileProcessor,
+ fileUtilsWrapper
+ )
+ isNonActionable = uploadedStatusDao.findByModifiedImageSHA1(
+ imageModifiedSHA1,
+ true
+ )
+ if (isNonActionable > 0) {
+ Toast.makeText(
+ this@ZoomableActivity,
+ "Can't select this image for upload",
+ Toast.LENGTH_SHORT
+ ).show()
+ } else {
+ if (!selectedImages!!.contains(images!![position])) {
+ selectedImages!!.add(images!![position])
+ }
+ position = getNextActionableImage(position + 1)
+ init(images!![position].uri)
+ }
+ }
+ }
+ }
+ }
+
+ override fun onSwipeDown() {
+ super.onSwipeDown()
+ scope.launch {
+ insertInNotForUpload(images!![position])
+ if (position < images!!.size - 1) {
+ position++
+ init(images!![position].uri)
+ } else {
+ Toast.makeText(
+ this@ZoomableActivity,
+ "No more images found",
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+ }
+ })
+ }
+ }
+
+ /**
+ * Gets next actionable image
+ */
+ private suspend fun getNextActionableImage(index: Int): Int {
+ var nextPosition = position
+ for(i in index until images!!.size){
+ nextPosition = i
+ val imageSHA1 = CustomSelectorUtils.getImageSHA1(
+ images!![i].uri,
+ ioDispatcher,
+ fileUtilsWrapper,
+ contentResolver
+ )
+ var isNonActionable = notForUploadStatusDao.find(imageSHA1)
+ if (isNonActionable <= 0) {
+ isNonActionable = uploadedStatusDao.findByImageSHA1(imageSHA1, true)
+ if (isNonActionable <= 0) {
+ val imageModifiedSHA1 = CustomSelectorUtils.generateModifiedSHA1(
+ images!![i],
+ defaultDispatcher,
+ this@ZoomableActivity,
+ fileProcessor,
+ fileUtilsWrapper
+ )
+ isNonActionable = uploadedStatusDao.findByModifiedImageSHA1(
+ imageModifiedSHA1,
+ true
+ )
+ if (isNonActionable <= 0) {
+ return i
+ } else {
+ continue
+ }
+ } else {
+ continue
+ }
+ } else {
+ continue
+ }
+ }
+ return nextPosition
+ }
+
+ /**
+ * Unselect item UI
+ */
+ private fun itemUnselected() {
+ selectedCount!!.visibility = View.INVISIBLE
+ }
+
+ /**
+ * Select item UI
+ */
+ private fun itemSelected(i: Int) {
+ selectedCount!!.visibility = View.VISIBLE
+ selectedCount!!.text = i.toString()
+ }
+
+ /**
+ * Get index from list
+ */
+ private fun getIndex(list: ArrayList?, image: Image): Int {
+ return list!!.indexOf(image)
+ }
+
+ /**
+ * Two types of loading indicators have been added to the zoom activity:
+ * 1. An Indeterminate spinner for showing the time lapsed between dispatch of the image request
+ * and starting to receiving the image.
+ * 2. ProgressBarDrawable that reflects how much image has been downloaded
+ */
+ private val loadingListener: ControllerListener =
+ object : BaseControllerListener() {
+ override fun onSubmit(id: String, callerContext: Any) {
+ // Sometimes the spinner doesn't appear when rapidly switching between images, this fixes that
+ spinner!!.visibility = View.VISIBLE
+ }
+
+ override fun onIntermediateImageSet(id: String, imageInfo: ImageInfo?) {
+ spinner!!.visibility = View.GONE
+ }
+
+ override fun onFinalImageSet(
+ id: String,
+ imageInfo: ImageInfo?,
+ animatable: Animatable?
+ ) {
+ spinner!!.visibility = View.GONE
+ }
+ }
+
+ private fun init(imageUri: Uri?) {
+ if (imageUri != null) {
+ val hierarchy = GenericDraweeHierarchyBuilder.newInstance(resources)
+ .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
+ .setProgressBarImage(ProgressBarDrawable())
+ .setProgressBarImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
+ .build()
+ photo!!.hierarchy = hierarchy
+ photo!!.setAllowTouchInterceptionWhileZoomed(true)
+ photo!!.setIsLongpressEnabled(false)
+ photo!!.setTapListener(DoubleTapGestureListener(photo))
+ val controller: DraweeController = Fresco.newDraweeControllerBuilder()
+ .setUri(imageUri)
+ .setControllerListener(loadingListener)
+ .build()
+ photo!!.controller = controller
+
+ if (!images.isNullOrEmpty()) {
+ val selectedIndex = getIndex(selectedImages, images!![position])
+ val isSelected = selectedIndex != -1
+ if (isSelected) {
+ itemSelected(selectedIndex + 1)
+ } else {
+ itemUnselected()
+ }
+ }
+ }
+ }
+
+ /**
+ * Inserts an image in Not For Upload Database
+ */
+ private suspend fun insertInNotForUpload(it: Image) {
+ val imageSHA1 = CustomSelectorUtils.getImageSHA1(
+ it.uri,
+ ioDispatcher,
+ fileUtilsWrapper,
+ contentResolver
+ )
+ notForUploadStatusDao.insert(
+ NotForUploadStatus(
+ imageSHA1,
+ true
+ )
+ )
+ }
+
+ /**
+ * Send selected images in fragment
+ */
+ override fun onBackPressed() {
+ if (!images.isNullOrEmpty()) {
+ val returnIntent = Intent()
+ returnIntent.putParcelableArrayListExtra(
+ CustomSelectorConstants.NEW_SELECTED_IMAGES,
+ selectedImages
+ )
+ setResult(Activity.RESULT_OK, returnIntent)
+ finish()
+ }
+ super.onBackPressed()
+ }
+
+ override fun onDestroy() {
+ scope.cancel()
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/fr/free/nrw/commons/utils/CustomSelectorUtils.kt b/app/src/main/java/fr/free/nrw/commons/utils/CustomSelectorUtils.kt
index 5d710cef0..fa426e626 100644
--- a/app/src/main/java/fr/free/nrw/commons/utils/CustomSelectorUtils.kt
+++ b/app/src/main/java/fr/free/nrw/commons/utils/CustomSelectorUtils.kt
@@ -5,6 +5,7 @@ import android.content.Context
import android.net.Uri
import androidx.exifinterface.media.ExifInterface
import fr.free.nrw.commons.customselector.model.Image
+import fr.free.nrw.commons.filepicker.PickedFiles
import fr.free.nrw.commons.customselector.ui.selector.ImageLoader
import fr.free.nrw.commons.filepicker.PickedFiles
import fr.free.nrw.commons.media.MediaClient
@@ -26,17 +27,18 @@ class CustomSelectorUtils {
/**
* Get image sha1 from uri, used to retrieve the original image sha1.
*/
- suspend fun getImageSHA1(uri: Uri,
- ioDispatcher : CoroutineDispatcher,
- fileUtilsWrapper: FileUtilsWrapper,
- contentResolver: ContentResolver
+ suspend fun getImageSHA1(
+ uri: Uri,
+ ioDispatcher: CoroutineDispatcher,
+ fileUtilsWrapper: FileUtilsWrapper,
+ contentResolver: ContentResolver
): String {
return withContext(ioDispatcher) {
try {
val result = fileUtilsWrapper.getSHA1(contentResolver.openInputStream(uri))
result
- } catch (e: FileNotFoundException){
+ } catch (e: FileNotFoundException) {
e.printStackTrace()
""
}
@@ -44,16 +46,15 @@ class CustomSelectorUtils {
}
/**
- * Generate Modified SHA1 using present Exif settings.
- *
- * @return modified sha1
+ * Generates modified SHA1 of an image
*/
- suspend fun generateModifiedSHA1(image: Image,
- defaultDispatcher : CoroutineDispatcher,
- context: Context,
- fileProcessor: FileProcessor,
- fileUtilsWrapper: FileUtilsWrapper
- ) : String {
+ suspend fun generateModifiedSHA1(
+ image: Image,
+ defaultDispatcher: CoroutineDispatcher,
+ context: Context,
+ fileProcessor: FileProcessor,
+ fileUtilsWrapper: FileUtilsWrapper
+ ): String {
return withContext(defaultDispatcher) {
val uploadableFile = PickedFiles.pickedExistingPicture(context, image.uri)
val exifInterface: ExifInterface? = try {
@@ -64,7 +65,9 @@ class CustomSelectorUtils {
}
fileProcessor.redactExifTags(exifInterface, fileProcessor.getExifTagsToRedact())
val sha1 =
- fileUtilsWrapper.getSHA1(fileUtilsWrapper.getFileInputStream(uploadableFile.filePath))
+ fileUtilsWrapper.getSHA1(
+ fileUtilsWrapper.getFileInputStream(uploadableFile.filePath)
+ )
uploadableFile.file.delete()
sha1
}
diff --git a/app/src/main/res/layout/activity_zoomable.xml b/app/src/main/res/layout/activity_zoomable.xml
index d022199e2..83c3d13be 100644
--- a/app/src/main/res/layout/activity_zoomable.xml
+++ b/app/src/main/res/layout/activity_zoomable.xml
@@ -23,4 +23,21 @@
app:layout_constraintTop_toTopOf="parent"
/>
+
+