From a6c4731f74f74a40153cb4bb0c465ca9908c55d8 Mon Sep 17 00:00:00 2001 From: Paul Hawke Date: Mon, 23 Dec 2024 11:41:46 -0600 Subject: [PATCH] Convert UploadModel to kotlin --- .../nrw/commons/contributions/Contribution.kt | 4 +- .../description/DescriptionEditActivity.kt | 4 +- .../nrw/commons/media/MediaDetailFragment.kt | 2 +- .../commons/repository/UploadRepository.kt | 4 +- .../free/nrw/commons/upload/FileProcessor.kt | 6 +- .../nrw/commons/upload/UploadMediaDetail.kt | 14 +- .../free/nrw/commons/upload/UploadModel.java | 297 ------------------ .../fr/free/nrw/commons/upload/UploadModel.kt | 242 ++++++++++++++ .../upload/categories/CategoriesPresenter.kt | 2 +- .../nrw/commons/upload/UploadModelUnitTest.kt | 2 +- .../upload/UploadRepositoryUnitTest.kt | 46 ++- 11 files changed, 282 insertions(+), 341 deletions(-) delete mode 100644 app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java create mode 100644 app/src/main/java/fr/free/nrw/commons/upload/UploadModel.kt diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt b/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt index 84ce0eb9c..a553d980e 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt +++ b/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt @@ -101,7 +101,7 @@ data class Contribution constructor( */ fun formatCaptions(uploadMediaDetails: List) = uploadMediaDetails - .associate { it.languageCode!! to it.captionText } + .associate { it.languageCode!! to it.captionText!! } .filter { it.value.isNotBlank() } /** @@ -112,7 +112,7 @@ data class Contribution constructor( */ fun formatDescriptions(descriptions: List) = descriptions - .filter { it.descriptionText.isNotEmpty() } + .filter { it.descriptionText!!.isNotEmpty() } .joinToString(separator = "") { "{{${it.languageCode}|1=${it.descriptionText}}}" } } diff --git a/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt b/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt index 3c6ad8653..412a8219c 100644 --- a/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/description/DescriptionEditActivity.kt @@ -272,11 +272,11 @@ class DescriptionEditActivity : applicationContext, media, mediaDetail.languageCode!!, - mediaDetail.captionText, + mediaDetail.captionText!!, ).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { s: Boolean? -> - updatedCaptions[mediaDetail.languageCode!!] = mediaDetail.captionText + updatedCaptions[mediaDetail.languageCode!!] = mediaDetail.captionText!! media.captions = updatedCaptions Timber.d("Caption is added.") }, diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt index 299f9b3be..66d9d08ef 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.kt @@ -1569,7 +1569,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C mediaDetail: UploadMediaDetail, updatedCaptions: MutableMap ) { - updatedCaptions[mediaDetail.languageCode!!] = mediaDetail.captionText + updatedCaptions[mediaDetail.languageCode!!] = mediaDetail.captionText!! media!!.captions = updatedCaptions } diff --git a/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.kt b/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.kt index f679960b9..4bf06eb61 100644 --- a/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.kt +++ b/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.kt @@ -69,7 +69,7 @@ class UploadRepository @Inject constructor( * @return */ fun getUploads(): List { - return uploadModel.getUploads() + return uploadModel.uploads } /** @@ -275,7 +275,7 @@ class UploadRepository @Inject constructor( * @param selectedExistingDepictions existing depicts */ fun setSelectedExistingDepictions(selectedExistingDepictions: List) { - uploadModel.selectedExistingDepictions = selectedExistingDepictions + uploadModel.selectedExistingDepictions = selectedExistingDepictions.toMutableList() } /** diff --git a/app/src/main/java/fr/free/nrw/commons/upload/FileProcessor.kt b/app/src/main/java/fr/free/nrw/commons/upload/FileProcessor.kt index 6bdcbdda7..617da88a0 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/FileProcessor.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/FileProcessor.kt @@ -52,7 +52,7 @@ class FileProcessor * Processes filePath coordinates, either from EXIF data or user location */ fun processFileCoordinates( - similarImageInterface: SimilarImageInterface, + similarImageInterface: SimilarImageInterface?, filePath: String?, inAppPictureLocation: LatLng?, ): ImageCoordinates { @@ -146,7 +146,7 @@ class FileProcessor */ private fun findOtherImages( fileBeingProcessed: File, - similarImageInterface: SimilarImageInterface, + similarImageInterface: SimilarImageInterface?, ) { val oneHundredAndTwentySeconds = 120 * 1000L // Time when the original image was created @@ -161,7 +161,7 @@ class FileProcessor .map { Pair(it, readImageCoordinates(it)) } .firstOrNull { it.second?.decimalCoords != null } ?.let { fileCoordinatesPair -> - similarImageInterface.showSimilarImageFragment( + similarImageInterface?.showSimilarImageFragment( fileBeingProcessed.path, fileCoordinatesPair.first.absolutePath, fileCoordinatesPair.second, diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadMediaDetail.kt b/app/src/main/java/fr/free/nrw/commons/upload/UploadMediaDetail.kt index 3756cee5b..a2b3168ec 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadMediaDetail.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadMediaDetail.kt @@ -8,7 +8,7 @@ import kotlinx.parcelize.Parcelize * Holds a description of an item being uploaded by [UploadActivity] */ @Parcelize -data class UploadMediaDetail constructor( +data class UploadMediaDetail( /** * The language code ie. "en" or "fr". * @param languageCode The language code ie. "en" or "fr". @@ -18,19 +18,19 @@ data class UploadMediaDetail constructor( * The description text for the item being uploaded. * @param descriptionText The description text. */ - var descriptionText: String = "", + var descriptionText: String? = "", /** * The caption text for the item being uploaded. * @param captionText The caption text. */ - var captionText: String = "", + var captionText: String? = "", ) : Parcelable { fun javaCopy() = copy() - constructor(place: Place) : this( - place.language, - place.longDescription, - place.name, + constructor(place: Place?) : this( + place?.language, + place?.longDescription, + place?.name, ) /** diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java deleted file mode 100644 index dfb7ae794..000000000 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java +++ /dev/null @@ -1,297 +0,0 @@ -package fr.free.nrw.commons.upload; - -import android.content.Context; -import android.net.Uri; -import fr.free.nrw.commons.Media; -import fr.free.nrw.commons.auth.SessionManager; -import fr.free.nrw.commons.contributions.Contribution; -import fr.free.nrw.commons.filepicker.UploadableFile; -import fr.free.nrw.commons.kvstore.JsonKvStore; -import fr.free.nrw.commons.location.LatLng; -import fr.free.nrw.commons.nearby.Place; -import fr.free.nrw.commons.settings.Prefs; -import fr.free.nrw.commons.upload.structure.depictions.DepictedItem; -import io.reactivex.Observable; -import io.reactivex.Single; -import io.reactivex.disposables.CompositeDisposable; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; -import org.jetbrains.annotations.NotNull; -import timber.log.Timber; - -@Singleton -public class UploadModel { - - private final JsonKvStore store; - private final List licenses; - private final Context context; - private String license; - private final Map licensesByName; - private final List items = new ArrayList<>(); - private final CompositeDisposable compositeDisposable = new CompositeDisposable(); - - private final SessionManager sessionManager; - private final FileProcessor fileProcessor; - private final ImageProcessingService imageProcessingService; - private final List selectedCategories = new ArrayList<>(); - private final List selectedDepictions = new ArrayList<>(); - /** - * Existing depicts which are selected - */ - private List selectedExistingDepictions = new ArrayList<>(); - - @Inject - UploadModel(@Named("licenses") final List licenses, - @Named("default_preferences") final JsonKvStore store, - @Named("licenses_by_name") final Map licensesByName, - final Context context, - final SessionManager sessionManager, - final FileProcessor fileProcessor, - final ImageProcessingService imageProcessingService) { - this.licenses = licenses; - this.store = store; - this.license = store.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3); - this.licensesByName = licensesByName; - this.context = context; - this.sessionManager = sessionManager; - this.fileProcessor = fileProcessor; - this.imageProcessingService = imageProcessingService; - } - - /** - * cleanup the resources, I am Singleton, preparing for fresh upload - */ - public void cleanUp() { - compositeDisposable.clear(); - fileProcessor.cleanup(); - items.clear(); - selectedCategories.clear(); - selectedDepictions.clear(); - selectedExistingDepictions.clear(); - } - - public void setSelectedCategories(List selectedCategories) { - this.selectedCategories.clear(); - this.selectedCategories.addAll(selectedCategories); - } - - /** - * pre process a one item at a time - */ - public Observable preProcessImage(final UploadableFile uploadableFile, - final Place place, - final SimilarImageInterface similarImageInterface, - LatLng inAppPictureLocation) { - return Observable.just( - createAndAddUploadItem(uploadableFile, place, similarImageInterface, inAppPictureLocation)); - } - - /** - * Calls validateImage() of ImageProcessingService to check quality of image - * - * @param uploadItem UploadItem whose quality is to be checked - * @param inAppPictureLocation In app picture location (if any) - * @return Quality of UploadItem - */ - public Single getImageQuality(final UploadItem uploadItem, LatLng inAppPictureLocation) { - return imageProcessingService.validateImage(uploadItem, inAppPictureLocation); - } - - /** - * Calls checkDuplicateImage() of ImageProcessingService to check if image is duplicate - * - * @param filePath file to be checked - * @return IMAGE_DUPLICATE or IMAGE_OK - */ - public Single checkDuplicateImage(String filePath){ - return imageProcessingService.checkDuplicateImage(filePath); - } - - /** - * Calls validateCaption() of ImageProcessingService to check caption of image - * - * @param uploadItem UploadItem whose caption is to be checked - * @return Quality of caption of the UploadItem - */ - public Single getCaptionQuality(final UploadItem uploadItem) { - return imageProcessingService.validateCaption(uploadItem); - } - - private UploadItem createAndAddUploadItem(final UploadableFile uploadableFile, - final Place place, - final SimilarImageInterface similarImageInterface, - LatLng inAppPictureLocation) { - final UploadableFile.DateTimeWithSource dateTimeWithSource = uploadableFile - .getFileCreatedDate(context); - long fileCreatedDate = -1; - String createdTimestampSource = ""; - String fileCreatedDateString = ""; - if (dateTimeWithSource != null) { - fileCreatedDate = dateTimeWithSource.getEpochDate(); - fileCreatedDateString = dateTimeWithSource.getDateString(); - createdTimestampSource = dateTimeWithSource.getSource(); - } - Timber.d("File created date is %d", fileCreatedDate); - final ImageCoordinates imageCoordinates = fileProcessor - .processFileCoordinates(similarImageInterface, uploadableFile.getFilePath(), - inAppPictureLocation); - final UploadItem uploadItem = new UploadItem( - Uri.parse(uploadableFile.getFilePath()), - uploadableFile.getMimeType(context), imageCoordinates, place, fileCreatedDate, - createdTimestampSource, - uploadableFile.getContentUri(), - fileCreatedDateString); - - // If an uploadItem of the same uploadableFile has been created before, we return that. - // This is to avoid multiple instances of uploadItem of same file passed around. - if (items.contains(uploadItem)) { - return items.get(items.indexOf(uploadItem)); - } - - if (place != null) { - uploadItem.getUploadMediaDetails().set(0, new UploadMediaDetail(place)); - } - if (!items.contains(uploadItem)) { - items.add(uploadItem); - } - return uploadItem; - } - - public int getCount() { - return items.size(); - } - - public List getUploads() { - return items; - } - - public List getLicenses() { - return licenses; - } - - public String getSelectedLicense() { - return license; - } - - public void setSelectedLicense(final String licenseName) { - this.license = licensesByName.get(licenseName); - store.putString(Prefs.DEFAULT_LICENSE, license); - } - - public Observable buildContributions() { - return Observable.fromIterable(items).map(item -> - { - String imageSHA1 = FileUtils.INSTANCE.getSHA1(context.getContentResolver().openInputStream(item.getContentUri())); - - final Contribution contribution = new Contribution( - item, sessionManager, newListOf(selectedDepictions), newListOf(selectedCategories), imageSHA1); - - contribution.setHasInvalidLocation(item.hasInvalidLocation()); - - Timber.d("Created timestamp while building contribution is %s, %s", - item.getCreatedTimestamp(), - new Date(item.getCreatedTimestamp())); - - if (item.getCreatedTimestamp() != -1L) { - contribution.setDateCreated(new Date(item.getCreatedTimestamp())); - contribution.setDateCreatedSource(item.getCreatedTimestampSource()); - //Set the date only if you have it, else the upload service is gonna try it the other way - } - - if (contribution.getWikidataPlace() != null) { - if (item.isWLMUpload()) { - contribution.getWikidataPlace().setMonumentUpload(true); - } else { - contribution.getWikidataPlace().setMonumentUpload(false); - } - } - contribution.setCountryCode(item.getCountryCode()); - return contribution; - }); - } - - public void deletePicture(final String filePath) { - final Iterator iterator = items.iterator(); - while (iterator.hasNext()) { - if (iterator.next().getMediaUri().toString().contains(filePath)) { - iterator.remove(); - break; - } - } - if (items.isEmpty()) { - cleanUp(); - } - } - - public List getItems() { - return items; - } - - public void onDepictItemClicked(DepictedItem depictedItem, Media media) { - if (media == null) { - if (depictedItem.isSelected()) { - selectedDepictions.add(depictedItem); - } else { - selectedDepictions.remove(depictedItem); - } - } else { - if (depictedItem.isSelected()) { - if (media.getDepictionIds().contains(depictedItem.getId())) { - selectedExistingDepictions.add(depictedItem.getId()); - } else { - selectedDepictions.add(depictedItem); - } - } else { - if (media.getDepictionIds().contains(depictedItem.getId())) { - selectedExistingDepictions.remove(depictedItem.getId()); - if (!media.getDepictionIds().contains(depictedItem.getId())) { - final List depictsList = new ArrayList<>(); - depictsList.add(depictedItem.getId()); - depictsList.addAll(media.getDepictionIds()); - media.setDepictionIds(depictsList); - } - } else { - selectedDepictions.remove(depictedItem); - } - } - } - } - - @NotNull - private List newListOf(final List items) { - return items != null ? new ArrayList<>(items) : new ArrayList<>(); - } - - public void useSimilarPictureCoordinates(final ImageCoordinates imageCoordinates, final int uploadItemIndex) { - fileProcessor.prePopulateCategoriesAndDepictionsBy(imageCoordinates); - items.get(uploadItemIndex).setGpsCoords(imageCoordinates); - } - - public List getSelectedDepictions() { - return selectedDepictions; - } - - /** - * Provides selected existing depicts - * - * @return selected existing depicts - */ - public List getSelectedExistingDepictions() { - return selectedExistingDepictions; - } - - /** - * Initialize existing depicts - * - * @param selectedExistingDepictions existing depicts - */ - public void setSelectedExistingDepictions(final List selectedExistingDepictions) { - this.selectedExistingDepictions = selectedExistingDepictions; - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.kt b/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.kt new file mode 100644 index 000000000..68ff30c4f --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.kt @@ -0,0 +1,242 @@ +package fr.free.nrw.commons.upload + +import android.content.Context +import android.net.Uri +import fr.free.nrw.commons.Media +import fr.free.nrw.commons.auth.SessionManager +import fr.free.nrw.commons.contributions.Contribution +import fr.free.nrw.commons.filepicker.UploadableFile +import fr.free.nrw.commons.kvstore.JsonKvStore +import fr.free.nrw.commons.location.LatLng +import fr.free.nrw.commons.nearby.Place +import fr.free.nrw.commons.settings.Prefs +import fr.free.nrw.commons.upload.FileUtils.getSHA1 +import fr.free.nrw.commons.upload.structure.depictions.DepictedItem +import io.reactivex.Observable +import io.reactivex.Single +import io.reactivex.disposables.CompositeDisposable +import timber.log.Timber +import java.util.Date +import javax.inject.Inject +import javax.inject.Named +import javax.inject.Singleton + +@Singleton +class UploadModel @Inject internal constructor( + @param:Named("licenses") val licenses: List, + @param:Named("default_preferences") val store: JsonKvStore, + @param:Named("licenses_by_name") val licensesByName: Map, + val context: Context, + val sessionManager: SessionManager, + val fileProcessor: FileProcessor, + val imageProcessingService: ImageProcessingService +) { + var license: String? = store.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3) + val items: MutableList = mutableListOf() + val compositeDisposable: CompositeDisposable = CompositeDisposable() + val selectedCategories: MutableList = mutableListOf() + val selectedDepictions: MutableList = mutableListOf() + + /** + * Existing depicts which are selected + */ + var selectedExistingDepictions: MutableList = mutableListOf() + val count: Int + get() = items.size + + val uploads: List + get() = items + + var selectedLicense: String? + get() = license + set(licenseName) { + license = licensesByName[licenseName] + if (license == null) { + store.remove(Prefs.DEFAULT_LICENSE) + } else { + store.putString(Prefs.DEFAULT_LICENSE, license!!) + } + } + + /** + * cleanup the resources, I am Singleton, preparing for fresh upload + */ + fun cleanUp() { + compositeDisposable.clear() + fileProcessor.cleanup() + items.clear() + selectedCategories.clear() + selectedDepictions.clear() + selectedExistingDepictions.clear() + } + + fun setSelectedCategories(categories: List) { + selectedCategories.clear() + selectedCategories.addAll(categories) + } + + /** + * pre process a one item at a time + */ + fun preProcessImage( + uploadableFile: UploadableFile?, + place: Place?, + similarImageInterface: SimilarImageInterface?, + inAppPictureLocation: LatLng? + ): Observable = Observable.just( + createAndAddUploadItem(uploadableFile, place, similarImageInterface, inAppPictureLocation) + ) + + /** + * Calls validateImage() of ImageProcessingService to check quality of image + * + * @param uploadItem UploadItem whose quality is to be checked + * @param inAppPictureLocation In app picture location (if any) + * @return Quality of UploadItem + */ + fun getImageQuality(uploadItem: UploadItem, inAppPictureLocation: LatLng?): Single = + imageProcessingService.validateImage(uploadItem, inAppPictureLocation) + + /** + * Calls checkDuplicateImage() of ImageProcessingService to check if image is duplicate + * + * @param filePath file to be checked + * @return IMAGE_DUPLICATE or IMAGE_OK + */ + fun checkDuplicateImage(filePath: String?): Single = + imageProcessingService.checkDuplicateImage(filePath) + + /** + * Calls validateCaption() of ImageProcessingService to check caption of image + * + * @param uploadItem UploadItem whose caption is to be checked + * @return Quality of caption of the UploadItem + */ + fun getCaptionQuality(uploadItem: UploadItem): Single = + imageProcessingService.validateCaption(uploadItem) + + private fun createAndAddUploadItem( + uploadableFile: UploadableFile?, + place: Place?, + similarImageInterface: SimilarImageInterface?, + inAppPictureLocation: LatLng? + ): UploadItem { + val dateTimeWithSource = uploadableFile?.getFileCreatedDate(context) + var fileCreatedDate: Long = -1 + var createdTimestampSource = "" + var fileCreatedDateString: String? = "" + if (dateTimeWithSource != null) { + fileCreatedDate = dateTimeWithSource.epochDate + fileCreatedDateString = dateTimeWithSource.dateString + createdTimestampSource = dateTimeWithSource.source + } + Timber.d("File created date is %d", fileCreatedDate) + val imageCoordinates = fileProcessor + .processFileCoordinates( + similarImageInterface, uploadableFile?.getFilePath(), + inAppPictureLocation + ) + val uploadItem = UploadItem( + Uri.parse(uploadableFile?.getFilePath()), + uploadableFile?.getMimeType(context), imageCoordinates, place, fileCreatedDate, + createdTimestampSource, + uploadableFile?.contentUri, + fileCreatedDateString + ) + + // If an uploadItem of the same uploadableFile has been created before, we return that. + // This is to avoid multiple instances of uploadItem of same file passed around. + if (items.contains(uploadItem)) { + return items[items.indexOf(uploadItem)] + } + + uploadItem.uploadMediaDetails[0] = UploadMediaDetail(place) + if (!items.contains(uploadItem)) { + items.add(uploadItem) + } + return uploadItem + } + + fun buildContributions(): Observable { + return Observable.fromIterable(items).map { item: UploadItem -> + val imageSHA1 = getSHA1( + context.contentResolver.openInputStream(item.contentUri!!)!! + ) + val contribution = Contribution( + item, + sessionManager, + buildList { addAll(selectedDepictions) }, + buildList { addAll(selectedCategories) }, + imageSHA1 + ) + + contribution.setHasInvalidLocation(item.hasInvalidLocation()) + + Timber.d( + "Created timestamp while building contribution is %s, %s", + item.createdTimestamp, + Date(item.createdTimestamp) + ) + + if (item.createdTimestamp != -1L) { + contribution.dateCreated = Date(item.createdTimestamp) + contribution.dateCreatedSource = item.createdTimestampSource + //Set the date only if you have it, else the upload service is gonna try it the other way + } + + if (contribution.wikidataPlace != null) { + contribution.wikidataPlace!!.isMonumentUpload = item.isWLMUpload + } + contribution.countryCode = item.countryCode + contribution + } + } + + fun deletePicture(filePath: String) { + val iterator = items.iterator() + while (iterator.hasNext()) { + if (iterator.next().mediaUri.toString().contains(filePath)) { + iterator.remove() + break + } + } + if (items.isEmpty()) { + cleanUp() + } + } + + fun onDepictItemClicked(depictedItem: DepictedItem, media: Media?) { + if (media == null) { + if (depictedItem.isSelected) { + selectedDepictions.add(depictedItem) + } else { + selectedDepictions.remove(depictedItem) + } + } else { + if (depictedItem.isSelected) { + if (media.depictionIds.contains(depictedItem.id)) { + selectedExistingDepictions.add(depictedItem.id) + } else { + selectedDepictions.add(depictedItem) + } + } else { + if (media.depictionIds.contains(depictedItem.id)) { + selectedExistingDepictions.remove(depictedItem.id) + if (!media.depictionIds.contains(depictedItem.id)) { + media.depictionIds = mutableListOf().apply { + add(depictedItem.id) + addAll(media.depictionIds) + } + } + } else { + selectedDepictions.remove(depictedItem) + } + } + } + } + + fun useSimilarPictureCoordinates(imageCoordinates: ImageCoordinates, uploadItemIndex: Int) { + fileProcessor.prePopulateCategoriesAndDepictionsBy(imageCoordinates) + items[uploadItemIndex].gpsCoords = imageCoordinates + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/upload/categories/CategoriesPresenter.kt b/app/src/main/java/fr/free/nrw/commons/upload/categories/CategoriesPresenter.kt index dbeeae6ff..7536cad75 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/categories/CategoriesPresenter.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/categories/CategoriesPresenter.kt @@ -140,7 +140,7 @@ class CategoriesPresenter */ private fun getImageTitleList(): List = repository.getUploads() - .map { it.uploadMediaDetails[0].captionText } + .map { it.uploadMediaDetails[0].captionText!! } .filterNot { TextUtils.isEmpty(it) } /** diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadModelUnitTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadModelUnitTest.kt index fb1f07e33..09f1acb58 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadModelUnitTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadModelUnitTest.kt @@ -140,6 +140,6 @@ class UploadModelUnitTest { @Ignore @Test fun testSetSelectedExistingDepictions() { - uploadModel.selectedExistingDepictions = listOf("") + uploadModel.selectedExistingDepictions = mutableListOf("") } } diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadRepositoryUnitTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadRepositoryUnitTest.kt index ac01d237f..9c022c936 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadRepositoryUnitTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadRepositoryUnitTest.kt @@ -1,7 +1,9 @@ package fr.free.nrw.commons.upload +import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever import fr.free.nrw.commons.Media import fr.free.nrw.commons.category.CategoriesModel import fr.free.nrw.commons.category.CategoryItem @@ -17,6 +19,7 @@ import fr.free.nrw.commons.upload.structure.depictions.DepictedItem import io.reactivex.Completable import io.reactivex.Observable import io.reactivex.Single +import org.junit.Assert.assertSame import org.junit.Before import org.junit.Test import org.junit.jupiter.api.Assertions.assertEquals @@ -118,7 +121,9 @@ class UploadRepositoryUnitTest { @Test fun testGetUploads() { - assertEquals(repository.getUploads(), uploadModel.uploads) + val result = listOf(uploadItem) + whenever(uploadModel.uploads).thenReturn(result) + assertSame(result, repository.getUploads()) } @Test @@ -136,10 +141,10 @@ class UploadRepositoryUnitTest { @Test fun testSearchAll() { - assertEquals( - repository.searchAll("", listOf(), listOf()), - categoriesModel.searchAll("", listOf(), listOf()), - ) + val empty = Observable.empty>() + whenever(categoriesModel.searchAll(any(), any(), any())).thenReturn(empty) + assertSame(empty, repository.searchAll("", listOf(), listOf())) + } @Test @@ -164,7 +169,9 @@ class UploadRepositoryUnitTest { @Test fun testGetLicenses() { - assertEquals(repository.getLicenses(), uploadModel.licenses) + whenever(uploadModel.licenses).thenReturn(listOf()) + repository.getLicenses() + verify(uploadModel).licenses } @Test @@ -208,10 +215,10 @@ class UploadRepositoryUnitTest { @Test fun testGetUploadItemCaseNonNull() { - `when`(uploadModel.items).thenReturn(listOf(uploadItem)) + `when`(uploadModel.items).thenReturn(mutableListOf(uploadItem)) assertEquals( repository.getUploadItem(0), - uploadModel.items[0], + uploadItem, ) } @@ -220,19 +227,6 @@ class UploadRepositoryUnitTest { assertEquals(repository.getUploadItem(-1), null) } - @Test - fun testSetSelectedLicense() { - assertEquals(repository.setSelectedLicense(""), uploadModel.setSelectedLicense("")) - } - - @Test - fun testSetSelectedExistingDepictions() { - assertEquals( - repository.setSelectedExistingDepictions(listOf("")), - uploadModel.setSelectedExistingDepictions(listOf("")), - ) - } - @Test fun testOnDepictItemClicked() { assertEquals( @@ -243,12 +237,14 @@ class UploadRepositoryUnitTest { @Test fun testGetSelectedDepictions() { - assertEquals(repository.getSelectedDepictions(), uploadModel.selectedDepictions) + repository.getSelectedDepictions() + verify(uploadModel).selectedDepictions } @Test fun testGetSelectedExistingDepictions() { - assertEquals(repository.getSelectedExistingDepictions(), uploadModel.selectedExistingDepictions) + repository.getSelectedExistingDepictions() + verify(uploadModel).selectedExistingDepictions } @Test @@ -324,8 +320,8 @@ class UploadRepositoryUnitTest { @Test fun testIsWMLSupportedForThisPlace() { - `when`(uploadModel.items).thenReturn(listOf(uploadItem)) - `when`(uploadItem.isWLMUpload).thenReturn(true) + whenever(uploadModel.items).thenReturn(mutableListOf(uploadItem)) + whenever(uploadItem.isWLMUpload).thenReturn(true) assertEquals( repository.isWMLSupportedForThisPlace(), true,