mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Merge 24e6ac7318 into aae9d4a387
This commit is contained in:
commit
ad69041a9c
7 changed files with 63 additions and 54 deletions
|
|
@ -10,4 +10,5 @@ object CustomSelectorConstants {
|
||||||
const val NEW_SELECTED_IMAGES = "new_selected_images"
|
const val NEW_SELECTED_IMAGES = "new_selected_images"
|
||||||
const val SHOULD_REFRESH = "should_refresh"
|
const val SHOULD_REFRESH = "should_refresh"
|
||||||
const val FULL_SCREEN_MODE_FIRST_LUNCH = "full_screen_mode_first_launch"
|
const val FULL_SCREEN_MODE_FIRST_LUNCH = "full_screen_mode_first_launch"
|
||||||
|
const val MAX_IMAGE_COUNT = 20
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import fr.free.nrw.commons.contributions.Contribution
|
||||||
import fr.free.nrw.commons.customselector.helper.ImageHelper
|
import fr.free.nrw.commons.customselector.helper.ImageHelper
|
||||||
import fr.free.nrw.commons.customselector.helper.ImageHelper.CUSTOM_SELECTOR_PREFERENCE_KEY
|
import fr.free.nrw.commons.customselector.helper.ImageHelper.CUSTOM_SELECTOR_PREFERENCE_KEY
|
||||||
import fr.free.nrw.commons.customselector.helper.ImageHelper.SHOW_ALREADY_ACTIONED_IMAGES_PREFERENCE_KEY
|
import fr.free.nrw.commons.customselector.helper.ImageHelper.SHOW_ALREADY_ACTIONED_IMAGES_PREFERENCE_KEY
|
||||||
|
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants.MAX_IMAGE_COUNT
|
||||||
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
|
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
|
||||||
|
|
@ -188,55 +189,38 @@ class ImageAdapter(
|
||||||
defaultDispatcher,
|
defaultDispatcher,
|
||||||
uploadingContributionList,
|
uploadingContributionList,
|
||||||
)
|
)
|
||||||
scope.launch {
|
|
||||||
val sharedPreferences: SharedPreferences =
|
|
||||||
context.getSharedPreferences(CUSTOM_SELECTOR_PREFERENCE_KEY, 0)
|
|
||||||
val showAlreadyActionedImages =
|
|
||||||
sharedPreferences.getBoolean(SHOW_ALREADY_ACTIONED_IMAGES_PREFERENCE_KEY, true)
|
|
||||||
if (!showAlreadyActionedImages) {
|
|
||||||
// If the position is not already visited, that means the position is new then
|
|
||||||
// finds the next actionable image position from all images
|
|
||||||
if (!alreadyAddedPositions.contains(position)) {
|
|
||||||
processThumbnailForActionedImage(
|
|
||||||
holder,
|
|
||||||
position,
|
|
||||||
uploadingContributionList
|
|
||||||
)
|
|
||||||
_isLoadingImages.value = false
|
|
||||||
// If the position is already visited, that means the image is already present
|
|
||||||
// inside map, so it will fetch the image from the map and load in the holder
|
|
||||||
} else {
|
|
||||||
val actionableImages: List<Image> = ArrayList(actionableImagesMap.values)
|
|
||||||
if (actionableImages.size > position) {
|
|
||||||
image = actionableImages[position]
|
|
||||||
Glide
|
|
||||||
.with(holder.image)
|
|
||||||
.load(image.uri)
|
|
||||||
.thumbnail(0.3f)
|
|
||||||
.into(holder.image)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If switch is turned off, it just fetches the image from all images without any
|
|
||||||
// further operations
|
|
||||||
} else {
|
|
||||||
Glide
|
|
||||||
.with(holder.image)
|
|
||||||
.load(image.uri)
|
|
||||||
.thumbnail(0.3f)
|
|
||||||
.into(holder.image)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.itemView.setOnClickListener {
|
holder.itemView.setOnClickListener {
|
||||||
onThumbnailClicked(position, holder)
|
if (!holder.isItemUploaded() && !holder.isItemNotForUpload()) {
|
||||||
|
if (selectedImages.size >= MAX_IMAGE_COUNT && !isSelected) { //enforce the 20-image limit
|
||||||
|
Toast.makeText(context, "Cannot select more than 20 images", Toast.LENGTH_SHORT).show()
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
if (isSelected) {
|
||||||
|
selectedImages.removeAt(selectedIndex)
|
||||||
|
holder.itemUnselected()
|
||||||
|
notifyItemChanged(position, ImageUnselected())
|
||||||
|
imageSelectListener.onSelectedImagesChanged(selectedImages, selectedImages.size)
|
||||||
|
} else {
|
||||||
|
selectedImages.add(image)
|
||||||
|
holder.itemSelected()
|
||||||
|
notifyItemChanged(position, ImageSelectedOrUpdated())
|
||||||
|
imageSelectListener.onSelectedImagesChanged(selectedImages, selectedImages.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// launch media preview on long click.
|
|
||||||
holder.itemView.setOnLongClickListener {
|
holder.itemView.setOnLongClickListener {
|
||||||
imageSelectListener.onLongPress(images.indexOf(image), images, selectedImages)
|
imageSelectListener.onLongPress(position, images, ArrayList(selectedImages))
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
//handle close button click for deselection
|
||||||
|
holder.closeButton.setOnClickListener {
|
||||||
|
if (isSelected) {
|
||||||
|
selectedImages.removeAt(selectedIndex)
|
||||||
|
holder.itemUnselected()
|
||||||
|
notifyItemChanged(position, ImageUnselected())
|
||||||
|
imageSelectListener.onSelectedImagesChanged(selectedImages, selectedImages.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,7 +401,7 @@ class ImageAdapter(
|
||||||
* Set new selected images
|
* Set new selected images
|
||||||
*/
|
*/
|
||||||
fun setSelectedImages(newSelectedImages: ArrayList<Image>) {
|
fun setSelectedImages(newSelectedImages: ArrayList<Image>) {
|
||||||
selectedImages = ArrayList(newSelectedImages)
|
selectedImages = ArrayList(newSelectedImages.take(MAX_IMAGE_COUNT)) // enforce 20-image limit
|
||||||
imageSelectListener.onSelectedImagesChanged(selectedImages, 0)
|
imageSelectListener.onSelectedImagesChanged(selectedImages, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -431,7 +415,7 @@ class ImageAdapter(
|
||||||
) {
|
) {
|
||||||
numberOfSelectedImagesMarkedAsNotForUpload = 0
|
numberOfSelectedImagesMarkedAsNotForUpload = 0
|
||||||
images.clear()
|
images.clear()
|
||||||
selectedImages = arrayListOf()
|
selectedImages = ArrayList(selectedImages.take(5)) // enforce the 5-image limit
|
||||||
init(newImages, fixedImages, TreeMap(), uploadingImages)
|
init(newImages, fixedImages, TreeMap(), uploadingImages)
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
@ -523,12 +507,14 @@ class ImageAdapter(
|
||||||
private val uploadingGroup: Group = itemView.findViewById(R.id.uploading_group)
|
private val uploadingGroup: Group = itemView.findViewById(R.id.uploading_group)
|
||||||
private val notForUploadGroup: Group = itemView.findViewById(R.id.not_for_upload_group)
|
private val notForUploadGroup: Group = itemView.findViewById(R.id.not_for_upload_group)
|
||||||
private val selectedGroup: Group = itemView.findViewById(R.id.selected_group)
|
private val selectedGroup: Group = itemView.findViewById(R.id.selected_group)
|
||||||
|
val closeButton: ImageView = itemView.findViewById(R.id.close_button) // Added for close button
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Item selected view.
|
* Item selected view.
|
||||||
*/
|
*/
|
||||||
fun itemSelected() {
|
fun itemSelected() {
|
||||||
selectedGroup.visibility = View.VISIBLE
|
selectedGroup.visibility = View.VISIBLE
|
||||||
|
closeButton.visibility = View.VISIBLE // Show close button when selected
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -536,6 +522,7 @@ class ImageAdapter(
|
||||||
*/
|
*/
|
||||||
fun itemUnselected() {
|
fun itemUnselected() {
|
||||||
selectedGroup.visibility = View.GONE
|
selectedGroup.visibility = View.GONE
|
||||||
|
closeButton.visibility = View.GONE // Hide close button when unselected
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ import fr.free.nrw.commons.customselector.database.NotForUploadStatus
|
||||||
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
|
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
|
||||||
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants
|
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants
|
||||||
import fr.free.nrw.commons.customselector.helper.FolderDeletionHelper
|
import fr.free.nrw.commons.customselector.helper.FolderDeletionHelper
|
||||||
|
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants.MAX_IMAGE_COUNT
|
||||||
import fr.free.nrw.commons.customselector.listeners.FolderClickListener
|
import fr.free.nrw.commons.customselector.listeners.FolderClickListener
|
||||||
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
|
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
|
||||||
import fr.free.nrw.commons.customselector.model.Image
|
import fr.free.nrw.commons.customselector.model.Image
|
||||||
|
|
@ -107,7 +108,7 @@ class CustomSelectorActivity :
|
||||||
/**
|
/**
|
||||||
* Maximum number of images that can be selected.
|
* Maximum number of images that can be selected.
|
||||||
*/
|
*/
|
||||||
private var uploadLimit: Int = 20
|
private var uploadLimit: Int = MAX_IMAGE_COUNT // changed to 20 asper the issue #3101
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag that is marked true when the amount
|
* Flag that is marked true when the amount
|
||||||
|
|
@ -214,7 +215,7 @@ class CustomSelectorActivity :
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check for single selection extra
|
// Check for single selection extra
|
||||||
uploadLimit = if (intent.getBooleanExtra(EXTRA_SINGLE_SELECTION, false)) 1 else 20
|
uploadLimit = if (intent.getBooleanExtra(EXTRA_SINGLE_SELECTION, false)) 1 else MAX_IMAGE_COUNT
|
||||||
|
|
||||||
setupViews()
|
setupViews()
|
||||||
|
|
||||||
|
|
@ -650,8 +651,12 @@ class CustomSelectorActivity :
|
||||||
finishPickImages(arrayListOf())
|
finishPickImages(arrayListOf())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (selectedImages.size > uploadLimit) {
|
||||||
|
displayUploadLimitWarning() // shows the warning dialog if >20 images
|
||||||
|
return
|
||||||
|
}
|
||||||
scope.launch(ioDispatcher) {
|
scope.launch(ioDispatcher) {
|
||||||
val uniqueImages = selectedImages.distinctBy { image ->
|
val uniqueImages = selectedImages.take(uploadLimit).distinctBy { image -> //enforce limit
|
||||||
CustomSelectorUtils.getImageSHA1(
|
CustomSelectorUtils.getImageSHA1(
|
||||||
image.uri,
|
image.uri,
|
||||||
ioDispatcher,
|
ioDispatcher,
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.facebook.drawee.view.SimpleDraweeView
|
import com.facebook.drawee.view.SimpleDraweeView
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
|
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants.MAX_IMAGE_COUNT
|
||||||
import fr.free.nrw.commons.databinding.ItemUploadThumbnailBinding
|
import fr.free.nrw.commons.databinding.ItemUploadThumbnailBinding
|
||||||
import fr.free.nrw.commons.filepicker.UploadableFile
|
import fr.free.nrw.commons.filepicker.UploadableFile
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
@ -23,7 +24,7 @@ internal class ThumbnailsAdapter(private val callback: Callback) :
|
||||||
var onThumbnailDeletedListener: OnThumbnailDeletedListener? = null
|
var onThumbnailDeletedListener: OnThumbnailDeletedListener? = null
|
||||||
var uploadableFiles: List<UploadableFile> = emptyList()
|
var uploadableFiles: List<UploadableFile> = emptyList()
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value.take(MAX_IMAGE_COUNT) //enforce 20-image limit
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.auth.LoginActivity
|
import fr.free.nrw.commons.auth.LoginActivity
|
||||||
import fr.free.nrw.commons.auth.SessionManager
|
import fr.free.nrw.commons.auth.SessionManager
|
||||||
import fr.free.nrw.commons.contributions.ContributionController
|
import fr.free.nrw.commons.contributions.ContributionController
|
||||||
|
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants.MAX_IMAGE_COUNT
|
||||||
import fr.free.nrw.commons.databinding.ActivityUploadBinding
|
import fr.free.nrw.commons.databinding.ActivityUploadBinding
|
||||||
import fr.free.nrw.commons.filepicker.Constants.RequestCodes
|
import fr.free.nrw.commons.filepicker.Constants.RequestCodes
|
||||||
import fr.free.nrw.commons.filepicker.UploadableFile
|
import fr.free.nrw.commons.filepicker.UploadableFile
|
||||||
|
|
@ -734,8 +735,8 @@ class UploadActivity : BaseActivity(), UploadContract.View, UploadBaseFragment.C
|
||||||
intent.getParcelableArrayListExtra<UploadableFile>(EXTRA_FILES)
|
intent.getParcelableArrayListExtra<UploadableFile>(EXTRA_FILES)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to mutable list or return empty list if null
|
// Convert to mutable list,takes up to 20 files, or return empty list if null
|
||||||
files?.toMutableList() ?: run {
|
files?.toMutableList()?.take(MAX_IMAGE_COUNT)?.toMutableList() ?: run { //enforce 20-image limit
|
||||||
Timber.w("Files array was null")
|
Timber.w("Files array was null")
|
||||||
mutableListOf()
|
mutableListOf()
|
||||||
}
|
}
|
||||||
|
|
@ -752,6 +753,9 @@ class UploadActivity : BaseActivity(), UploadContract.View, UploadBaseFragment.C
|
||||||
Timber.d("File $index path: ${file.getFilePath()}")
|
Timber.d("File $index path: ${file.getFilePath()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update thumbnails adapter with limited files
|
||||||
|
thumbnailsAdapter?.uploadableFiles = uploadableFiles
|
||||||
|
|
||||||
// Handle other extras with null safety
|
// Handle other extras with null safety
|
||||||
place = try {
|
place = try {
|
||||||
if (VERSION.SDK_INT >= VERSION_CODES.TIRAMISU) {
|
if (VERSION.SDK_INT >= VERSION_CODES.TIRAMISU) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
|
@ -45,14 +44,24 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/close_button"
|
||||||
|
android:layout_width="@dimen/dimen_20"
|
||||||
|
android:layout_height="@dimen/dimen_20"
|
||||||
|
app:layout_constraintDimensionRatio="H,1:1"
|
||||||
|
android:src="@drawable/ic_cancel_white"
|
||||||
|
android:layout_margin="@dimen/dimen_6"
|
||||||
|
android:background="@drawable/circle_shape"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Group
|
<androidx.constraintlayout.widget.Group
|
||||||
android:id="@+id/selected_group"
|
android:id="@+id/selected_group"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:constraint_referenced_ids="selected_overlay,selected_image"/>
|
app:constraint_referenced_ids="selected_overlay,selected_image,close_button"/>
|
||||||
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/uploaded_overlay"
|
android:id="@+id/uploaded_overlay"
|
||||||
|
|
|
||||||
|
|
@ -887,4 +887,6 @@ Upload your first media by tapping on the add button.</string>
|
||||||
<string name="image_tag_line_created_and_uploaded_by">Created and uploaded by: %1$s</string>
|
<string name="image_tag_line_created_and_uploaded_by">Created and uploaded by: %1$s</string>
|
||||||
<string name="image_tag_line_created_by_and_uploaded_by">Created by %1$s and uploaded by %2$s</string>
|
<string name="image_tag_line_created_by_and_uploaded_by">Created by %1$s and uploaded by %2$s</string>
|
||||||
<string name="nominated_for_deletion_btn">Nominated for Deletion</string>
|
<string name="nominated_for_deletion_btn">Nominated for Deletion</string>
|
||||||
|
|
||||||
|
<string name="custom_selector_limit_warning_message">You can only select up to 20 images.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue