[GSoC] Full Screen Mode (#5032)

* Gesture detection implemented

* Left and right swipe

* Selection implemented

* onDown implemented

* onDown implemented

* FS mode implemented

* OnSwipe doc

* Scope cancel

* Added label in Manifest
This commit is contained in:
Ayan Sarkar 2022-08-20 15:51:36 +05:30 committed by GitHub
parent a6c51a75a8
commit 52912087d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 579 additions and 115 deletions

View file

@ -46,7 +46,10 @@
android:finishOnTaskLaunch="true" />
<activity
android:name=".media.ZoomableActivity" />
android:name=".media.ZoomableActivity"
android:label="Zoomable Activity"
android:configChanges="screenSize|keyboard|orientation"
android:parentActivityName=".customselector.ui.selector.CustomSelectorActivity" />
<activity android:name=".auth.LoginActivity">
<intent-filter>

View file

@ -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
}

View file

@ -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"
}

View file

@ -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())
}
}

View file

@ -19,5 +19,9 @@ interface ImageSelectListener {
* onLongPress
* @param imageUri : uri of image
*/
fun onLongPress(imageUri: Uri)
fun onLongPress(
position: Int,
images: ArrayList<Image>,
selectedImages: ArrayList<Image>
)
}

View file

@ -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<Image>)
}

View file

@ -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<Image>){
selectedImages = ArrayList(newSelectedImages)
imageSelectListener.onSelectedImagesChanged(selectedImages, 0)
}
/**
* Refresh the data in the adapter
*/

View file

@ -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<Image> =
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<Image>,
selectedImages: ArrayList<Image>
) {
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)
}
/**

View file

@ -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<Image>){
imageAdapter.setSelectedImages(selectedImages)
}
}

View file

@ -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();
}

View file

@ -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<ImageInfo>() {
@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);
}
}
}

View file

@ -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<Image>? = null
/**
* Total selected images present in folder
*/
private var selectedImages: ArrayList<Image>? = 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: 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<ImageInfo?> =
object : BaseControllerListener<ImageInfo?>() {
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()
}
}

View file

@ -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,7 +27,8 @@ class CustomSelectorUtils {
/**
* Get image sha1 from uri, used to retrieve the original image sha1.
*/
suspend fun getImageSHA1(uri: Uri,
suspend fun getImageSHA1(
uri: Uri,
ioDispatcher: CoroutineDispatcher,
fileUtilsWrapper: FileUtilsWrapper,
contentResolver: ContentResolver
@ -44,11 +46,10 @@ class CustomSelectorUtils {
}
/**
* Generate Modified SHA1 using present Exif settings.
*
* @return modified sha1
* Generates modified SHA1 of an image
*/
suspend fun generateModifiedSHA1(image: Image,
suspend fun generateModifiedSHA1(
image: Image,
defaultDispatcher: CoroutineDispatcher,
context: Context,
fileProcessor: FileProcessor,
@ -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
}

View file

@ -23,4 +23,21 @@
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/selection_count"
android:layout_width="@dimen/dimen_20"
android:layout_height="@dimen/dimen_20"
app:layout_constraintDimensionRatio="H,1:1"
android:textSize="11sp"
android:textStyle="bold"
android:textColor="@color/black"
android:layout_margin="@dimen/dimen_6"
android:gravity="center|center_vertical"
style="@style/TextAppearance.AppCompat.Small"
android:text="12"
android:visibility="gone"
android:background="@drawable/circle_shape"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>