Copy Title, description and location to subsequent media (#487)

* Copy Title, description and location to subsequent media

* Show message on success

* Refresh UI immediately after location update

Refactor location handling in UploadMediaDetailFragment and related classes
This commit is contained in:
Sujal-Gupta-SG 2025-04-04 21:58:25 +05:30
parent 44966645ca
commit 1c4dc21ca4
3 changed files with 64 additions and 18 deletions

View file

@ -21,6 +21,8 @@ import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.exifinterface.media.ExifInterface import androidx.exifinterface.media.ExifInterface
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.viewpager.widget.ViewPager
import androidx.viewpager2.widget.ViewPager2
import fr.free.nrw.commons.CameraPosition import fr.free.nrw.commons.CameraPosition
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.contributions.MainActivity import fr.free.nrw.commons.contributions.MainActivity
@ -215,21 +217,7 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
btnPrevious.alpha = 1.0f btnPrevious.alpha = 1.0f
} }
// If the image EXIF data contains the location, show the map icon with a green tick updateMapTickIcon(0)
if (inAppPictureLocation != null || (uploadableFile != null && uploadableFile!!.hasLocation())) {
val mapTick =
ContextCompat.getDrawable(requireContext(), R.drawable.ic_map_available_20dp)
locationImageView.setImageDrawable(mapTick)
locationTextView.setText(R.string.edit_location)
} else {
// Otherwise, show the map icon with a red question mark
val mapQuestionMark = ContextCompat.getDrawable(
requireContext(),
R.drawable.ic_map_not_available_20dp
)
locationImageView.setImageDrawable(mapQuestionMark)
locationTextView.setText(R.string.add_location)
}
//If this is the last media, we have nothing to copy, lets not show the button //If this is the last media, we have nothing to copy, lets not show the button
btnCopySubsequentMedia.visibility = btnCopySubsequentMedia.visibility =
@ -323,6 +311,7 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
) )
binding.locationImageView.setImageDrawable(mapTick) binding.locationImageView.setImageDrawable(mapTick)
binding.locationTextView.setText(R.string.edit_location) binding.locationTextView.setText(R.string.edit_location)
updateMapTickIcon(0)
} }
override fun onNegativeResponse() { override fun onNegativeResponse() {
@ -437,6 +426,7 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
if (fragmentCallback == null) { if (fragmentCallback == null) {
return return
} }
updateMapTickIcon(this.indexOfFragment)
presenter.fetchTitleAndDescription(indexOfFragment) presenter.fetchTitleAndDescription(indexOfFragment)
if (showNearbyFound) { if (showNearbyFound) {
if (UploadActivity.nearbyPopupAnswers!!.containsKey(nearbyPlace!!)) { if (UploadActivity.nearbyPopupAnswers!!.containsKey(nearbyPlace!!)) {
@ -718,6 +708,8 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
binding.locationTextView.setText(R.string.add_location) binding.locationTextView.setText(R.string.add_location)
} }
updateMapTickIcon(this.indexOfFragment) // Refresh UI immediately
editableUploadItem!!.gpsCoords!!.decLatitude = 0.0 editableUploadItem!!.gpsCoords!!.decLatitude = 0.0
editableUploadItem!!.gpsCoords!!.decLongitude = 0.0 editableUploadItem!!.gpsCoords!!.decLongitude = 0.0
editableUploadItem!!.gpsCoords!!.imageCoordsExists = false editableUploadItem!!.gpsCoords!!.imageCoordsExists = false
@ -871,6 +863,32 @@ class UploadMediaDetailFragment : UploadBaseFragment(), UploadMediaDetailsContra
Toast.makeText(context, R.string.copied_successfully, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.copied_successfully, Toast.LENGTH_SHORT).show()
} }
private fun updateMapTickIcon(index: Int) {
if (_binding == null) return
editableUploadItem = presenter.getUploadItem(index)
val hasLocation = (!hasUserRemovedLocation) && (
inAppPictureLocation != null ||
(uploadableFile != null && uploadableFile!!.hasLocation()) ||
(editableUploadItem?.gpsCoords?.imageCoordsExists == true &&
editableUploadItem?.gpsCoords?.decimalCoords != null)
)
binding.locationImageView.setImageDrawable(
ContextCompat.getDrawable(
requireContext(),
if (hasLocation) R.drawable.ic_map_available_20dp
else R.drawable.ic_map_not_available_20dp
)
)
binding.locationTextView.setText(
if (hasLocation) R.string.edit_location
else R.string.add_location
)
}
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)

View file

@ -124,5 +124,7 @@ interface UploadMediaDetailsContract {
fun onEditButtonClicked(indexInViewFlipper: Int) fun onEditButtonClicked(indexInViewFlipper: Int)
fun onUserConfirmedUploadIsOfPlace(place: Place?, uploadItemIndex: Int) fun onUserConfirmedUploadIsOfPlace(place: Place?, uploadItemIndex: Int)
fun getUploadItem(index: Int): UploadItem?
} }
} }

View file

@ -205,15 +205,42 @@ class UploadMediaPresenter @Inject constructor(
/** /**
* Copies the caption and description of the current item to the subsequent media * Copies the caption. location and description of the current item to the subsequent media
*/ */
override fun copyTitleAndDescriptionToSubsequentMedia(indexInViewFlipper: Int) { override fun copyTitleAndDescriptionToSubsequentMedia(indexInViewFlipper: Int) {
val sourceItem = repository.getUploads()[indexInViewFlipper]
for (i in indexInViewFlipper + 1 until repository.getCount()) { for (i in indexInViewFlipper + 1 until repository.getCount()) {
val subsequentUploadItem = repository.getUploads()[i] val subsequentUploadItem = repository.getUploads()[i]
subsequentUploadItem.uploadMediaDetails = deepCopy( subsequentUploadItem.uploadMediaDetails = deepCopy(
repository.getUploads()[indexInViewFlipper].uploadMediaDetails sourceItem.uploadMediaDetails
).toMutableList() ).toMutableList()
sourceItem.gpsCoords?.let { sourceCoords ->
if (sourceCoords.decimalCoords != null) {
if (subsequentUploadItem.gpsCoords == null) {
val latLng = sourceCoords.latLng
if (latLng != null) {
subsequentUploadItem.gpsCoords = ImageCoordinates(null, latLng)
} }
} else {
subsequentUploadItem.gpsCoords!!.decLatitude = sourceCoords.decLatitude
subsequentUploadItem.gpsCoords!!.decLongitude = sourceCoords.decLongitude
subsequentUploadItem.gpsCoords!!.decimalCoords = sourceCoords.decimalCoords
subsequentUploadItem.gpsCoords!!.imageCoordsExists = true
subsequentUploadItem.gpsCoords!!.zoomLevel = sourceCoords.zoomLevel
}
}
}
}
view?.showMessage("Title, description and location copied to subsequent media",
android.R.color.holo_green_light)
}
override fun getUploadItem(index: Int): UploadItem? {
return repository.getUploads().getOrNull(index)
} }
/** /**
@ -256,7 +283,6 @@ class UploadMediaPresenter @Inject constructor(
setUploadIsOfAPlace(true) setUploadIsOfAPlace(true)
} }
/** /**
* Calculates the image quality * Calculates the image quality
* *