#3699 Multiple upload: Only one file's caption is used for all files, others ignored - share model data with the UI - inline and remove Remote/LocalDataSource (#3707)

This commit is contained in:
Seán Mac Gillicuddy 2020-05-08 11:21:17 +01:00 committed by GitHub
parent 11ff5fb055
commit 4443810823
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 341 additions and 704 deletions

View file

@ -6,7 +6,7 @@ import androidx.room.PrimaryKey;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.upload.UploadMediaDetail;
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
import fr.free.nrw.commons.upload.UploadItem;
import fr.free.nrw.commons.upload.WikidataPlace;
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
import java.util.ArrayList;

View file

@ -1,151 +0,0 @@
package fr.free.nrw.commons.repository;
import androidx.annotation.Nullable;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.upload.UploadModel;
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
/**
* The Local Data Source for UploadRepository, fetches and returns data from local db/shared prefernces
*/
@Singleton
public class UploadLocalDataSource {
private final UploadModel uploadModel;
private JsonKvStore defaultKVStore;
@Inject
public UploadLocalDataSource(
@Named("default_preferences") JsonKvStore defaultKVStore,
UploadModel uploadModel) {
this.defaultKVStore = defaultKVStore;
this.uploadModel = uploadModel;
}
/**
* Fetches and returns the string list of valid licenses
*
* @return
*/
public List<String> getLicenses() {
return uploadModel.getLicenses();
}
/**
* Returns the number of Upload Items
*
* @return
*/
public int getCount() {
return uploadModel.getCount();
}
/**
* Fetches and return the selected license for the current upload
*
* @return
*/
public String getSelectedLicense() {
return uploadModel.getSelectedLicense();
}
/**
* Set selected license for the current upload
*
* @param licenseName
*/
public void setSelectedLicense(String licenseName) {
uploadModel.setSelectedLicense(licenseName);
}
/**
* Updates the current upload item
*
* @param index
* @param uploadItem
*/
public void updateUploadItem(int index, UploadItem uploadItem) {
uploadModel.updateUploadItem(index, uploadItem);
}
/**
* upload is halted, cleanup the acquired resources
*/
public void cleanUp() {
uploadModel.cleanUp();
}
/**
* Deletes the upload item at the current index
*
* @param filePath
*/
public void deletePicture(String filePath) {
uploadModel.deletePicture(filePath);
}
/**
* Fethces and returns the previous upload item, if any, returns null otherwise
*
* @param index
* @return
*/
@Nullable
public UploadItem getPreviousUploadItem(int index) {
if (index - 1 >= 0) {
return uploadModel.getItems().get(index - 1);
}
return null; //There is no previous item to copy details
}
/**
* saves boolean value in default store
*
* @param key
* @param value
*/
public void saveValue(String key, boolean value) {
defaultKVStore.putBoolean(key, value);
}
/**
* saves string value in default store
*
* @param key
* @param value
*/
public void saveValue(String key, String value) {
defaultKVStore.putString(key, value);
}
/**
* Fetches and returns string value from the default store
*
* @param key
* @param defaultValue
* @return
*/
public String getValue(String key, String defaultValue) {
return defaultKVStore.getString(key, defaultValue);
}
/**
* Fetches and returns boolean value from the default store
*
* @param key
* @param defaultValue
* @return
*/
public boolean getValue(String key, boolean defaultValue) {
return defaultKVStore.getBoolean(key, defaultValue);
}
}

View file

@ -1,230 +0,0 @@
package fr.free.nrw.commons.repository;
import fr.free.nrw.commons.category.CategoriesModel;
import fr.free.nrw.commons.category.CategoryItem;
import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.filepicker.UploadableFile;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.nearby.NearbyPlaces;
import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.upload.ImageCoordinates;
import fr.free.nrw.commons.upload.SimilarImageInterface;
import fr.free.nrw.commons.upload.UploadController;
import fr.free.nrw.commons.upload.UploadModel;
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
import fr.free.nrw.commons.upload.structure.depictions.DepictModel;
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.Single;
import java.io.IOException;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* This class would act as the data source for remote operations for UploadActivity
*/
@Singleton
public class UploadRemoteDataSource {
private static final double NEARBY_RADIUS_IN_KILO_METERS = 0.1; //100 meters
private UploadModel uploadModel;
private UploadController uploadController;
private CategoriesModel categoriesModel;
private DepictModel depictModel;
private NearbyPlaces nearbyPlaces;
@Inject
public UploadRemoteDataSource(UploadModel uploadModel, UploadController uploadController,
CategoriesModel categoriesModel, NearbyPlaces nearbyPlaces, DepictModel depictModel) {
this.uploadModel = uploadModel;
this.uploadController = uploadController;
this.categoriesModel = categoriesModel;
this.nearbyPlaces = nearbyPlaces;
this.depictModel = depictModel;
}
/**
* asks the UploadModel to build the contributions
*
* @return
*/
public Observable<Contribution> buildContributions() {
return uploadModel.buildContributions();
}
/**
* asks the UploadService to star the uplaod for
*
* @param contribution
*/
public void startUpload(Contribution contribution) {
uploadController.startUpload(contribution);
}
/**
* returns the list of UploadItem from the UploadModel
*
* @return
*/
public List<UploadItem> getUploads() {
return uploadModel.getUploads();
}
/**
* Prepare the UploadService for the upload
*/
public void prepareService() {
uploadController.prepareService();
}
/**
* Clean up the selected categories
*/
public void cleanUp(){
//This needs further refactoring, this should not be here, right now the structure wont suppoort rhis
categoriesModel.cleanUp();
depictModel.cleanUp();
}
/**
* returnt the list of selected categories
*
* @return
*/
public List<CategoryItem> getSelectedCategories() {
return categoriesModel.getSelectedCategories();
}
/**
* all categories from MWApi
*
* @param query
* @param imageTitleList
* @return
*/
public Observable<CategoryItem> searchAll(String query, List<String> imageTitleList) {
return categoriesModel.searchAll(query, imageTitleList);
}
/**
* returns the string list of categories
*
* @return
*/
public List<String> getCategoryStringList() {
return categoriesModel.getCategoryStringList();
}
/**
* sets the selected categories in the UploadModel
*
* @param categoryStringList
*/
public void setSelectedCategories(List<String> categoryStringList) {
uploadModel.setSelectedCategories(categoryStringList);
}
/**
* handles category selection/unselection
*
* @param categoryItem
*/
public void onCategoryClicked(CategoryItem categoryItem) {
categoriesModel.onCategoryItemClicked(categoryItem);
}
/**
* returns category sorted based on similarity with query
*
* @param query
* @return
*/
public Comparator<CategoryItem> sortBySimilarity(String query) {
return categoriesModel.sortBySimilarity(query);
}
/**
* prunes the category list for irrelevant categories see #750
*
* @param name
* @return
*/
public boolean containsYear(String name) {
return categoriesModel.containsYear(name);
}
/**
* pre process the UploadableFile
*
* @param uploadableFile
* @param place
* @param similarImageInterface
* @return
*/
public Observable<UploadItem> preProcessImage(UploadableFile uploadableFile, Place place,
SimilarImageInterface similarImageInterface) {
return uploadModel.preProcessImage(uploadableFile, place, similarImageInterface);
}
/**
* ask the UplaodModel for the image quality of the UploadItem
*
* @param uploadItem
* @return
*/
public Single<Integer> getImageQuality(UploadItem uploadItem) {
return uploadModel.getImageQuality(uploadItem);
}
/**
* gets nearby places matching with upload item's GPS location
*
* @param latitude
* @param longitude
* @return
*/
public Place getNearbyPlaces(double latitude, double longitude) throws IOException {
List<Place> fromWikidataQuery = nearbyPlaces
.getFromWikidataQuery(new LatLng(latitude, longitude, 0.0f),
Locale.getDefault().getLanguage(),
NEARBY_RADIUS_IN_KILO_METERS);
return fromWikidataQuery.size() > 0 ? fromWikidataQuery.get(0) : null;
}
/**
* handles category selection/unselection
* @param depictedItem
*/
public void onDepictedItemClicked(DepictedItem depictedItem) {
uploadModel.onDepictItemClicked(depictedItem);
}
/**
* returns the list of selected depictions
* @return
*/
public List<DepictedItem> getSelectedDepictions() {
return uploadModel.getSelectedDepictions();
}
/**
* get all depictions
* @return
*/
public Flowable<List<DepictedItem>> searchAllEntities(String query) {
return depictModel.searchAllEntities(query);
}
public void useSimilarPictureCoordinates(ImageCoordinates imageCoordinates, int uploadItemIndex) {
uploadModel.useSimilarPictureCoordinates(imageCoordinates, uploadItemIndex);
}
}

View file

@ -1,24 +1,28 @@
package fr.free.nrw.commons.repository;
import fr.free.nrw.commons.upload.ImageCoordinates;
import io.reactivex.Flowable;
import java.io.IOException;
import java.util.Comparator;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import fr.free.nrw.commons.category.CategoriesModel;
import fr.free.nrw.commons.category.CategoryItem;
import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.filepicker.UploadableFile;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.nearby.NearbyPlaces;
import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.upload.ImageCoordinates;
import fr.free.nrw.commons.upload.SimilarImageInterface;
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
import fr.free.nrw.commons.upload.UploadController;
import fr.free.nrw.commons.upload.UploadItem;
import fr.free.nrw.commons.upload.UploadModel;
import fr.free.nrw.commons.upload.structure.depictions.DepictModel;
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.Single;
import java.io.IOException;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* The repository class for UploadActivity
@ -26,14 +30,25 @@ import io.reactivex.Single;
@Singleton
public class UploadRepository {
private UploadLocalDataSource localDataSource;
private UploadRemoteDataSource remoteDataSource;
private final UploadModel uploadModel;
private final UploadController uploadController;
private final CategoriesModel categoriesModel;
private final NearbyPlaces nearbyPlaces;
private final DepictModel depictModel;
private static final double NEARBY_RADIUS_IN_KILO_METERS = 0.1; //100 meters
@Inject
public UploadRepository(UploadLocalDataSource localDataSource,
UploadRemoteDataSource remoteDataSource) {
this.localDataSource = localDataSource;
this.remoteDataSource = remoteDataSource;
public UploadRepository(UploadModel uploadModel,
UploadController uploadController,
CategoriesModel categoriesModel,
NearbyPlaces nearbyPlaces,
DepictModel depictModel) {
this.uploadModel = uploadModel;
this.uploadController = uploadController;
this.categoriesModel = categoriesModel;
this.nearbyPlaces = nearbyPlaces;
this.depictModel = depictModel;
}
/**
@ -42,7 +57,7 @@ public class UploadRepository {
* @return
*/
public Observable<Contribution> buildContributions() {
return remoteDataSource.buildContributions();
return uploadModel.buildContributions();
}
/**
@ -51,7 +66,7 @@ public class UploadRepository {
* @param contribution
*/
public void startUpload(Contribution contribution) {
remoteDataSource.startUpload(contribution);
uploadController.startUpload(contribution);
}
/**
@ -60,22 +75,24 @@ public class UploadRepository {
* @return
*/
public List<UploadItem> getUploads() {
return remoteDataSource.getUploads();
return uploadModel.getUploads();
}
/**
* asks the RemoteDataSource to prepare the Upload Service
*/
public void prepareService() {
remoteDataSource.prepareService();
uploadController.prepareService();
}
/**
*Prepare for a fresh upload
*/
public void cleanup() {
localDataSource.cleanUp();
remoteDataSource.cleanUp();
uploadModel.cleanUp();
//This needs further refactoring, this should not be here, right now the structure wont suppoort rhis
categoriesModel.cleanUp();
depictModel.cleanUp();
}
/**
@ -84,7 +101,7 @@ public class UploadRepository {
* @return
*/
public List<CategoryItem> getSelectedCategories() {
return remoteDataSource.getSelectedCategories();
return categoriesModel.getSelectedCategories();
}
/**
@ -95,7 +112,7 @@ public class UploadRepository {
* @return
*/
public Observable<CategoryItem> searchAll(String query, List<String> imageTitleList) {
return remoteDataSource.searchAll(query, imageTitleList);
return categoriesModel.searchAll(query, imageTitleList);
}
/**
@ -105,7 +122,7 @@ public class UploadRepository {
*/
public List<String> getCategoryStringList() {
return remoteDataSource.getCategoryStringList();
return categoriesModel.getCategoryStringList();
}
/**
@ -114,7 +131,7 @@ public class UploadRepository {
* @param categoryStringList
*/
public void setSelectedCategories(List<String> categoryStringList) {
remoteDataSource.setSelectedCategories(categoryStringList);
uploadModel.setSelectedCategories(categoryStringList);
}
/**
@ -123,7 +140,7 @@ public class UploadRepository {
* @param categoryItem
*/
public void onCategoryClicked(CategoryItem categoryItem) {
remoteDataSource.onCategoryClicked(categoryItem);
categoriesModel.onCategoryItemClicked(categoryItem);
}
/**
@ -133,7 +150,7 @@ public class UploadRepository {
* @return
*/
public Comparator<? super CategoryItem> sortBySimilarity(String query) {
return remoteDataSource.sortBySimilarity(query);
return categoriesModel.sortBySimilarity(query);
}
/**
@ -143,7 +160,7 @@ public class UploadRepository {
* @return
*/
public boolean containsYear(String name) {
return remoteDataSource.containsYear(name);
return categoriesModel.containsYear(name);
}
/**
@ -152,7 +169,7 @@ public class UploadRepository {
* @return
*/
public List<String> getLicenses() {
return localDataSource.getLicenses();
return uploadModel.getLicenses();
}
/**
@ -161,7 +178,7 @@ public class UploadRepository {
* @return
*/
public String getSelectedLicense() {
return localDataSource.getSelectedLicense();
return uploadModel.getSelectedLicense();
}
/**
@ -170,7 +187,7 @@ public class UploadRepository {
* @return
*/
public int getCount() {
return localDataSource.getCount();
return uploadModel.getCount();
}
/**
@ -183,7 +200,8 @@ public class UploadRepository {
*/
public Observable<UploadItem> preProcessImage(UploadableFile uploadableFile, Place place,
SimilarImageInterface similarImageInterface) {
return remoteDataSource.preProcessImage(uploadableFile, place, similarImageInterface);
return uploadModel.preProcessImage(uploadableFile, place,
similarImageInterface);
}
/**
@ -193,17 +211,7 @@ public class UploadRepository {
* @return
*/
public Single<Integer> getImageQuality(UploadItem uploadItem) {
return remoteDataSource.getImageQuality(uploadItem);
}
/**
* asks the LocalDataSource to update the Upload Item
*
* @param index
* @param uploadItem
*/
public void updateUploadItem(int index, UploadItem uploadItem) {
localDataSource.updateUploadItem(index, uploadItem);
return uploadModel.getImageQuality(uploadItem);
}
/**
@ -212,7 +220,7 @@ public class UploadRepository {
* @param filePath
*/
public void deletePicture(String filePath) {
localDataSource.deletePicture(filePath);
uploadModel.deletePicture(filePath);
}
/**
@ -222,38 +230,10 @@ public class UploadRepository {
* @return
*/
public UploadItem getPreviousUploadItem(int index) {
return localDataSource.getPreviousUploadItem(index);
}
/**
* Save boolean value locally
*
* @param key
* @param value
*/
public void saveValue(String key, boolean value) {
localDataSource.saveValue(key, value);
}
/**
* save string value locally
*
* @param key
* @param value
*/
public void saveValue(String key, String value) {
localDataSource.saveValue(key, value);
}
/**
* fetch the string value for the associated key
*
* @param key
* @param value
* @return
*/
public String getValue(String key, String value) {
return localDataSource.getValue(key, value);
if (index - 1 >= 0) {
return uploadModel.getItems().get(index - 1);
}
return null; //There is no previous item to copy details
}
/**
@ -262,11 +242,11 @@ public class UploadRepository {
* @param licenseName
*/
public void setSelectedLicense(String licenseName) {
localDataSource.setSelectedLicense(licenseName);
uploadModel.setSelectedLicense(licenseName);
}
public void onDepictItemClicked(DepictedItem depictedItem) {
remoteDataSource.onDepictedItemClicked(depictedItem);
uploadModel.onDepictItemClicked(depictedItem);
}
/**
@ -276,7 +256,7 @@ public class UploadRepository {
*/
public List<DepictedItem> getSelectedDepictions() {
return remoteDataSource.getSelectedDepictions();
return uploadModel.getSelectedDepictions();
}
/**
@ -287,7 +267,7 @@ public class UploadRepository {
*/
public Flowable<List<DepictedItem>> searchAllEntities(String query) {
return remoteDataSource.searchAllEntities(query);
return depictModel.searchAllEntities(query);
}
/**
@ -296,11 +276,19 @@ public class UploadRepository {
* @param decLongitude
* @return
*/
public Place checkNearbyPlaces(double decLatitude, double decLongitude) throws IOException {
return remoteDataSource.getNearbyPlaces(decLatitude, decLongitude);
public Place checkNearbyPlaces(double decLatitude, double decLongitude) {
try {
List<Place> fromWikidataQuery = nearbyPlaces.getFromWikidataQuery(new LatLng(
decLatitude, decLongitude, 0.0f),
Locale.getDefault().getLanguage(),
NEARBY_RADIUS_IN_KILO_METERS);
return fromWikidataQuery.size() > 0 ? fromWikidataQuery.get(0) : null;
} catch (IOException e) {
return null;
}
}
public void useSimilarPictureCoordinates(ImageCoordinates imageCoordinates, int uploadItemIndex) {
remoteDataSource.useSimilarPictureCoordinates(imageCoordinates, uploadItemIndex);
uploadModel.useSimilarPictureCoordinates(imageCoordinates, uploadItemIndex);
}
}

View file

@ -45,7 +45,7 @@ public class ImageProcessingService {
* Check image quality before upload - checks duplicate image - checks dark image - checks
* geolocation for image - check for valid title
*/
Single<Integer> validateImage(UploadModel.UploadItem uploadItem) {
Single<Integer> validateImage(UploadItem uploadItem) {
int currentImageQuality = uploadItem.getImageQuality();
Timber.d("Current image quality is %d", currentImageQuality);
if (currentImageQuality == ImageUtils.IMAGE_KEEP) {
@ -97,7 +97,7 @@ public class ImageProcessingService {
* @param uploadItem
* @return
*/
private Single<Integer> validateItemTitle(UploadModel.UploadItem uploadItem) {
private Single<Integer> validateItemTitle(UploadItem uploadItem) {
Timber.d("Checking for image title %s", uploadItem.getUploadMediaDetails());
List<UploadMediaDetail> captions = uploadItem.getUploadMediaDetails();
if (captions.isEmpty()) {

View file

@ -0,0 +1,106 @@
package fr.free.nrw.commons.upload;
import android.annotation.SuppressLint;
import android.net.Uri;
import androidx.annotation.Nullable;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.filepicker.MimeTypeMapWrapper;
import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.utils.ImageUtils;
import io.reactivex.subjects.BehaviorSubject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class UploadItem {
private final Uri mediaUri;
private final String mimeType;
private ImageCoordinates gpsCoords;
private List<UploadMediaDetail> uploadMediaDetails;
private final Place place;
private final long createdTimestamp;
private final String createdTimestampSource;
private final BehaviorSubject<Integer> imageQuality;
@SuppressLint("CheckResult")
UploadItem(final Uri mediaUri,
final String mimeType,
final ImageCoordinates gpsCoords,
final Place place,
final long createdTimestamp,
final String createdTimestampSource) {
this.createdTimestampSource = createdTimestampSource;
uploadMediaDetails = new ArrayList<>(Collections.singletonList(new UploadMediaDetail()));
this.place = place;
this.mediaUri = mediaUri;
this.mimeType = mimeType;
this.gpsCoords = gpsCoords;
this.createdTimestamp = createdTimestamp;
imageQuality = BehaviorSubject.createDefault(ImageUtils.IMAGE_WAIT);
}
public String getCreatedTimestampSource() {
return createdTimestampSource;
}
public ImageCoordinates getGpsCoords() {
return gpsCoords;
}
public List<UploadMediaDetail> getUploadMediaDetails() {
return uploadMediaDetails;
}
public long getCreatedTimestamp() {
return createdTimestamp;
}
public Uri getMediaUri() {
return mediaUri;
}
public int getImageQuality() {
return imageQuality.getValue();
}
public void setImageQuality(final int imageQuality) {
this.imageQuality.onNext(imageQuality);
}
public Place getPlace() {
return place;
}
public void setMediaDetails(final List<UploadMediaDetail> uploadMediaDetails) {
this.uploadMediaDetails = uploadMediaDetails;
}
@Override
public boolean equals(@Nullable final Object obj) {
if (!(obj instanceof UploadItem)) {
return false;
}
return mediaUri.toString().contains(((UploadItem) (obj)).mediaUri.toString());
}
@Override
public int hashCode() {
return mediaUri.hashCode();
}
/**
* Choose a filename for the media. Currently, the caption is used as a filename. If several
* languages have been entered, the first language is used.
*/
public String getFileName() {
return Utils.fixExtension(uploadMediaDetails.get(0).getCaptionText(),
MimeTypeMapWrapper.getExtensionFromMimeType(mimeType));
}
public void setGpsCoords(final ImageCoordinates gpsCoords) {
this.gpsCoords = gpsCoords;
}
}

View file

@ -17,6 +17,8 @@ data class UploadMediaDetail constructor(
var descriptionText: String = "",
var captionText: String = ""
) {
fun javaCopy() = copy()
constructor(place: Place) : this(
Locale.getDefault().language,
place.longDescription,

View file

@ -1,25 +1,18 @@
package fr.free.nrw.commons.upload;
import android.annotation.SuppressLint;
import android.content.Context;
import android.net.Uri;
import androidx.annotation.Nullable;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.filepicker.MimeTypeMapWrapper;
import fr.free.nrw.commons.filepicker.UploadableFile;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
import fr.free.nrw.commons.utils.ImageUtils;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.subjects.BehaviorSubject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
@ -44,8 +37,8 @@ public class UploadModel {
private final SessionManager sessionManager;
private final FileProcessor fileProcessor;
private final ImageProcessingService imageProcessingService;
private List<String> selectedCategories = new ArrayList<>();
private List<DepictedItem> selectedDepictions = new ArrayList<>();
private final List<String> selectedCategories = new ArrayList<>();
private final List<DepictedItem> selectedDepictions = new ArrayList<>();
@Inject
UploadModel(@Named("licenses") final List<String> licenses,
@ -77,7 +70,8 @@ public class UploadModel {
}
public void setSelectedCategories(List<String> selectedCategories) {
this.selectedCategories = selectedCategories;
this.selectedCategories.clear();
this.selectedCategories.addAll(selectedCategories);
}
/**
@ -150,7 +144,7 @@ public class UploadModel {
Timber.d("Created timestamp while building contribution is %s, %s",
item.getCreatedTimestamp(),
new Date(item.getCreatedTimestamp()));
if (item.createdTimestamp != -1L) {
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
@ -162,7 +156,7 @@ public class UploadModel {
public void deletePicture(final String filePath) {
final Iterator<UploadItem> iterator = items.iterator();
while (iterator.hasNext()) {
if (iterator.next().mediaUri.toString().contains(filePath)) {
if (iterator.next().getMediaUri().toString().contains(filePath)) {
iterator.remove();
break;
}
@ -176,11 +170,6 @@ public class UploadModel {
return items;
}
public void updateUploadItem(final int index, final UploadItem uploadItem) {
final UploadItem uploadItem1 = items.get(index);
uploadItem1.setMediaDetails(uploadItem.uploadMediaDetails);
}
public void onDepictItemClicked(DepictedItem depictedItem) {
if (depictedItem.isSelected()) {
selectedDepictions.add(depictedItem);
@ -202,97 +191,4 @@ public class UploadModel {
public List<DepictedItem> getSelectedDepictions() {
return selectedDepictions;
}
@SuppressWarnings("WeakerAccess")
public static class UploadItem {
private final Uri mediaUri;
private final String mimeType;
private ImageCoordinates gpsCoords;
private List<UploadMediaDetail> uploadMediaDetails;
private final Place place;
private final long createdTimestamp;
private final String createdTimestampSource;
private final BehaviorSubject<Integer> imageQuality;
@SuppressLint("CheckResult")
UploadItem(final Uri mediaUri,
final String mimeType,
final ImageCoordinates gpsCoords,
final Place place,
final long createdTimestamp,
final String createdTimestampSource) {
this.createdTimestampSource = createdTimestampSource;
uploadMediaDetails = new ArrayList<>(Arrays.asList(new UploadMediaDetail()));
this.place = place;
this.mediaUri = mediaUri;
this.mimeType = mimeType;
this.gpsCoords = gpsCoords;
this.createdTimestamp = createdTimestamp;
imageQuality = BehaviorSubject.createDefault(ImageUtils.IMAGE_WAIT);
}
public String getCreatedTimestampSource() {
return createdTimestampSource;
}
public ImageCoordinates getGpsCoords() {
return gpsCoords;
}
public List<UploadMediaDetail> getUploadMediaDetails() {
return uploadMediaDetails;
}
public long getCreatedTimestamp() {
return createdTimestamp;
}
public Uri getMediaUri() {
return mediaUri;
}
public int getImageQuality() {
return this.imageQuality.getValue();
}
public void setImageQuality(final int imageQuality) {
this.imageQuality.onNext(imageQuality);
}
public Place getPlace() {
return place;
}
public void setMediaDetails(final List<UploadMediaDetail> uploadMediaDetails) {
this.uploadMediaDetails = uploadMediaDetails;
}
@Override
public boolean equals(@Nullable final Object obj) {
if (!(obj instanceof UploadItem)) {
return false;
}
return this.mediaUri.toString().contains(((UploadItem) (obj)).mediaUri.toString());
}
@Override
public int hashCode() {
return mediaUri.hashCode();
}
/**
* Choose a filename for the media.
* Currently, the caption is used as a filename. If several languages have been entered, the first language is used.
*/
public String getFileName() {
return Utils.fixExtension(uploadMediaDetails.get(0).getCaptionText(),
MimeTypeMapWrapper.getExtensionFromMimeType(mimeType));
}
public void setGpsCoords(final ImageCoordinates gpsCoords) {
this.gpsCoords = gpsCoords;
}
}
}

View file

@ -30,7 +30,7 @@ public interface UploadView {
boolean checkIfLoggedIn();
void updateThumbnails(List<UploadModel.UploadItem> uploads);
void updateThumbnails(List<UploadItem> uploads);
void setNextEnabled(boolean available);
@ -54,7 +54,7 @@ public interface UploadView {
void updateRightCardContent(boolean gpsPresent);
void updateBottomCardContent(int currentStep, int stepCount, UploadModel.UploadItem uploadItem, boolean isShowingItem);
void updateBottomCardContent(int currentStep, int stepCount, UploadItem uploadItem, boolean isShowingItem);
void updateLicenses(List<String> licenses, String selectedLicense);

View file

@ -7,7 +7,7 @@ import android.text.TextUtils;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.category.CategoryItem;
import fr.free.nrw.commons.repository.UploadRepository;
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
import fr.free.nrw.commons.upload.UploadItem;
import io.reactivex.Observable;
import io.reactivex.Scheduler;
import io.reactivex.disposables.CompositeDisposable;

View file

@ -1,14 +1,14 @@
package fr.free.nrw.commons.upload.license;
import java.lang.reflect.Proxy;
import java.util.List;
import javax.inject.Inject;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.repository.UploadRepository;
import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.upload.license.MediaLicenseContract.View;
import java.lang.reflect.Proxy;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import timber.log.Timber;
/**
@ -23,11 +23,14 @@ public class MediaLicensePresenter implements MediaLicenseContract.UserActionLis
(proxy, method, methodArgs) -> null);
private final UploadRepository repository;
private final JsonKvStore defaultKVStore;
private MediaLicenseContract.View view = DUMMY;
@Inject
public MediaLicensePresenter(UploadRepository uploadRepository) {
public MediaLicensePresenter(UploadRepository uploadRepository,
@Named("default_preferences") JsonKvStore defaultKVStore) {
this.repository = uploadRepository;
this.defaultKVStore = defaultKVStore;
}
@Override
@ -48,14 +51,14 @@ public class MediaLicensePresenter implements MediaLicenseContract.UserActionLis
List<String> licenses = repository.getLicenses();
view.setLicenses(licenses);
String selectedLicense = repository.getValue(Prefs.DEFAULT_LICENSE,
String selectedLicense = defaultKVStore.getString(Prefs.DEFAULT_LICENSE,
Prefs.Licenses.CC_BY_SA_4);//CC_BY_SA_4 is the default one used by the commons web app
try {//I have to make sure that the stored default license was not one of the deprecated one's
Utils.licenseNameFor(selectedLicense);
} catch (IllegalStateException exception) {
Timber.e(exception.getMessage());
selectedLicense = Prefs.Licenses.CC_BY_SA_4;
repository.saveValue(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_4);
defaultKVStore.putString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_4);
}
view.setSelectedLicense(selectedLicense);

View file

@ -31,8 +31,7 @@ import fr.free.nrw.commons.upload.SimilarImageDialogFragment;
import fr.free.nrw.commons.upload.UploadBaseFragment;
import fr.free.nrw.commons.upload.UploadMediaDetail;
import fr.free.nrw.commons.upload.UploadMediaDetailAdapter;
import fr.free.nrw.commons.upload.UploadModel;
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
import fr.free.nrw.commons.upload.UploadItem;
import fr.free.nrw.commons.utils.DialogUtil;
import fr.free.nrw.commons.utils.ImageUtils;
import fr.free.nrw.commons.utils.ViewUtil;
@ -45,8 +44,6 @@ import javax.inject.Named;
import org.apache.commons.lang3.StringUtils;
import timber.log.Timber;
//import fr.free.nrw.commons.upload.DescriptionsAdapter;
public class UploadMediaDetailFragment extends UploadBaseFragment implements
UploadMediaDetailsContract.View, UploadMediaDetailAdapter.EventListener {
@ -70,9 +67,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
@BindView(R.id.btn_copy_prev_title_desc)
AppCompatButton btnCopyPreviousTitleDesc;
private UploadModel.UploadItem uploadItem;
private List<UploadMediaDetail> descriptions;
@Inject
UploadMediaDetailsContract.UserActionListener presenter;
@ -181,8 +175,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
@OnClick(R.id.btn_next)
public void onNextButtonClicked() {
uploadItem.setMediaDetails(uploadMediaDetailAdapter.getUploadMediaDetails());
presenter.verifyImageQuality(uploadItem);
presenter.verifyImageQuality(callback.getIndexInViewFlipper(this));
}
@OnClick(R.id.btn_previous)
@ -222,10 +215,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
@Override
public void onImageProcessed(UploadItem uploadItem, Place place) {
this.uploadItem = uploadItem;
descriptions = uploadItem.getUploadMediaDetails();
photoViewBackgroundImage.setImageURI(uploadItem.getMediaUri());
setDescriptionsInAdapter(descriptions);
}
/**
@ -242,8 +232,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
getString(R.string.upload_nearby_place_found_description),
place.getName()),
() -> {
descriptions = new ArrayList<>(Arrays.asList(new UploadMediaDetail(place)));
setDescriptionsInAdapter(descriptions);
presenter.onUserConfirmedUploadIsOfPlace(place, callback.getIndexInViewFlipper(this));
},
() -> {
@ -257,7 +246,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
@Override
public void onImageValidationSuccess() {
presenter.setUploadItem(callback.getIndexInViewFlipper(this), uploadItem);
callback.onNextButtonClicked(callback.getIndexInViewFlipper(this));
}
@ -272,7 +260,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
}
@Override
public void showDuplicatePicturePopup() {
public void showDuplicatePicturePopup(UploadItem uploadItem) {
String uploadTitleFormat = getString(R.string.upload_title_duplicate);
DialogUtil.showAlertDialog(getActivity(),
getString(R.string.duplicate_image_found),
@ -289,7 +277,8 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
}
@Override
public void showBadImagePopup(Integer errorCode) {
public void showBadImagePopup(Integer errorCode,
UploadItem uploadItem) {
String errorMessageForResult = getErrorMessageForResult(getContext(), errorCode);
if (!StringUtils.isBlank(errorMessageForResult)) {
DialogUtil.showAlertDialog(getActivity(),
@ -312,8 +301,15 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
}
@Override
public void setCaptionsAndDescriptions(List<UploadMediaDetail> uploadMediaDetails) {
setDescriptionsInAdapter(uploadMediaDetails);
public void showExternalMap(UploadItem uploadItem) {
Utils.handleGeoCoordinates(getContext(),
new LatLng(uploadItem.getGpsCoords().getDecLatitude(),
uploadItem.getGpsCoords().getDecLongitude(), 0.0f));
}
@Override
public void updateMediaDetails(List<UploadMediaDetail> uploadMediaDetails) {
uploadMediaDetailAdapter.setItems(uploadMediaDetails);
}
private void deleteThisPicture() {
@ -342,9 +338,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
}
@OnClick(R.id.ib_map) public void onIbMapClicked() {
Utils.handleGeoCoordinates(getContext(),
new LatLng(uploadItem.getGpsCoords().getDecLatitude(),
uploadItem.getGpsCoords().getDecLongitude(), 0.0f));
presenter.onMapIconClicked(callback.getIndexInViewFlipper(this));
}
@Override
@ -354,7 +348,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
btnNext.setAlpha(isNotEmpty ? 1.0f: 0.5f);
}
public interface UploadMediaDetailFragmentCallback extends Callback {
void deletePictureAtIndex(int index);
@ -366,7 +359,4 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
presenter.fetchPreviousTitleAndDescription(callback.getIndexInViewFlipper(this));
}
private void setDescriptionsInAdapter(List<UploadMediaDetail> uploadMediaDetails){
uploadMediaDetailAdapter.setItems(uploadMediaDetails);
}
}

View file

@ -6,7 +6,7 @@ import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.upload.ImageCoordinates;
import fr.free.nrw.commons.upload.SimilarImageInterface;
import fr.free.nrw.commons.upload.UploadMediaDetail;
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
import fr.free.nrw.commons.upload.UploadItem;
import java.util.List;
/**
@ -28,27 +28,30 @@ public interface UploadMediaDetailsContract {
void showMessage(String message, int colorResourceId);
void showDuplicatePicturePopup();
void showDuplicatePicturePopup(UploadItem uploadItem);
void showBadImagePopup(Integer errorCode);
void showBadImagePopup(Integer errorCode, UploadItem uploadItem);
void showMapWithImageCoordinates(boolean shouldShow);
void setCaptionsAndDescriptions(List<UploadMediaDetail> uploadMediaDetails);
void showExternalMap(UploadItem uploadItem);
void updateMediaDetails(List<UploadMediaDetail> uploadMediaDetails);
}
interface UserActionListener extends BasePresenter<View> {
void receiveImage(UploadableFile uploadableFile, Place place);
void verifyImageQuality(UploadItem uploadItem);
void setUploadItem(int index, UploadItem uploadItem);
void verifyImageQuality(int uploadItemIndex);
void fetchPreviousTitleAndDescription(int indexInViewFlipper);
void useSimilarPictureCoordinates(ImageCoordinates imageCoordinates, int uploadItemIndex);
void onMapIconClicked(int indexInViewFlipper);
void onUserConfirmedUploadIsOfPlace(Place place, int uploadItemPosition);
}
}

View file

@ -9,11 +9,13 @@ import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.filepicker.UploadableFile;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.repository.UploadRepository;
import fr.free.nrw.commons.upload.ImageCoordinates;
import fr.free.nrw.commons.upload.SimilarImageInterface;
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
import fr.free.nrw.commons.upload.UploadItem;
import fr.free.nrw.commons.upload.UploadMediaDetail;
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailsContract.UserActionListener;
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailsContract.View;
import io.reactivex.Maybe;
@ -21,8 +23,11 @@ import io.reactivex.Scheduler;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import org.jetbrains.annotations.NotNull;
import timber.log.Timber;
public class UploadMediaPresenter implements UserActionListener, SimilarImageInterface {
@ -38,14 +43,17 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
private CompositeDisposable compositeDisposable;
private final JsonKvStore defaultKVStore;
private Scheduler ioScheduler;
private Scheduler mainThreadScheduler;
@Inject
public UploadMediaPresenter(UploadRepository uploadRepository,
@Named("default_preferences") JsonKvStore defaultKVStore,
@Named(IO_THREAD) Scheduler ioScheduler,
@Named(MAIN_THREAD) Scheduler mainThreadScheduler) {
this.repository = uploadRepository;
this.defaultKVStore = defaultKVStore;
this.ioScheduler = ioScheduler;
this.mainThreadScheduler = mainThreadScheduler;
compositeDisposable = new CompositeDisposable();
@ -70,22 +78,25 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
@Override
public void receiveImage(UploadableFile uploadableFile, Place place) {
view.showProgress(true);
Disposable uploadItemDisposable = repository
compositeDisposable.add(
repository
.preProcessImage(uploadableFile, place, this)
.subscribeOn(ioScheduler)
.observeOn(mainThreadScheduler)
.subscribe(uploadItem ->
{
view.onImageProcessed(uploadItem, place);
ImageCoordinates gpsCoords = uploadItem.getGpsCoords();
view.showMapWithImageCoordinates(gpsCoords != null && gpsCoords.getImageCoordsExists());
view.showProgress(false);
if (gpsCoords != null && gpsCoords.getImageCoordsExists()) {
checkNearbyPlaces(uploadItem);
}
},
throwable -> Timber.e(throwable, "Error occurred in pre-processing images"));
compositeDisposable.add(uploadItemDisposable);
{
view.onImageProcessed(uploadItem, place);
view.updateMediaDetails(uploadItem.getUploadMediaDetails());
ImageCoordinates gpsCoords = uploadItem.getGpsCoords();
final boolean hasImageCoordinates =
gpsCoords != null && gpsCoords.getImageCoordsExists();
view.showMapWithImageCoordinates(hasImageCoordinates);
view.showProgress(false);
if (hasImageCoordinates) {
checkNearbyPlaces(uploadItem);
}
},
throwable -> Timber.e(throwable, "Error occurred in processing images")));
}
/**
@ -110,19 +121,20 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
/**
* asks the repository to verify image quality
*
* @param uploadItem
* @param uploadItemIndex
*/
@Override
public void verifyImageQuality(UploadItem uploadItem) {
public void verifyImageQuality(int uploadItemIndex) {
view.showProgress(true);
compositeDisposable.add(
final UploadItem uploadItem = repository.getUploads().get(uploadItemIndex);
compositeDisposable.add(
repository
.getImageQuality(uploadItem)
.observeOn(mainThreadScheduler)
.subscribe(imageResult -> {
view.showProgress(false);
handleImageResult(imageResult);
handleImageResult(imageResult, uploadItem);
},
throwable -> {
view.showProgress(false);
@ -133,16 +145,6 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
);
}
/**
* Adds the corresponding upload item to the repository
*
* @param index
* @param uploadItem
*/
@Override
public void setUploadItem(int index, UploadItem uploadItem) {
repository.updateUploadItem(index, uploadItem);
}
/**
* Fetches and sets the caption and desctiption of the previous item
@ -152,28 +154,55 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
@Override
public void fetchPreviousTitleAndDescription(int indexInViewFlipper) {
UploadItem previousUploadItem = repository.getPreviousUploadItem(indexInViewFlipper);
if (null != previousUploadItem) {
view.setCaptionsAndDescriptions(previousUploadItem.getUploadMediaDetails());
if (null != previousUploadItem) {
final UploadItem currentUploadItem = repository.getUploads().get(indexInViewFlipper);
currentUploadItem.setMediaDetails(deepCopy(previousUploadItem.getUploadMediaDetails()));
view.updateMediaDetails(currentUploadItem.getUploadMediaDetails());
} else {
view.showMessage(R.string.previous_image_title_description_not_found, R.color.color_error);
}
}
@NotNull
private List<UploadMediaDetail> deepCopy(List<UploadMediaDetail> uploadMediaDetails) {
final ArrayList<UploadMediaDetail> newList = new ArrayList<>();
for (UploadMediaDetail uploadMediaDetail : uploadMediaDetails) {
newList.add(uploadMediaDetail.javaCopy());
}
return newList;
}
@Override
public void useSimilarPictureCoordinates(ImageCoordinates imageCoordinates, int uploadItemIndex) {
repository.useSimilarPictureCoordinates(imageCoordinates, uploadItemIndex);
}
@Override
public void onMapIconClicked(int indexInViewFlipper) {
view.showExternalMap(repository.getUploads().get(indexInViewFlipper));
}
@Override
public void onUserConfirmedUploadIsOfPlace(Place place, int uploadItemPosition) {
final List<UploadMediaDetail> uploadMediaDetails = repository.getUploads()
.get(uploadItemPosition)
.getUploadMediaDetails();
uploadMediaDetails.set(0, new UploadMediaDetail(place));
view.updateMediaDetails(uploadMediaDetails);
}
/**
* handles image quality verifications
*
* @param imageResult
*/
public void handleImageResult(Integer imageResult) {
* @param imageResult
* @param uploadItem
*/
public void handleImageResult(Integer imageResult,
UploadItem uploadItem) {
if (imageResult == IMAGE_KEEP || imageResult == IMAGE_OK) {
view.onImageValidationSuccess();
} else {
handleBadImage(imageResult);
handleBadImage(imageResult, uploadItem);
}
}
@ -181,12 +210,13 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
* Handle images, say empty caption, duplicate file name, bad picture(in all other cases)
*
* @param errorCode
* @param uploadItem
*/
public void handleBadImage(Integer errorCode) {
public void handleBadImage(Integer errorCode, UploadItem uploadItem) {
Timber.d("Handle bad picture with error code %d", errorCode);
if (errorCode
>= 8) { // If location of image and nearby does not match, then set shared preferences to disable wikidata edits
repository.saveValue("Picture_Has_Correct_Location", false);
// If location of image and nearby does not match, then set shared preferences to disable wikidata edits
if (errorCode >= 8) {
defaultKVStore.putBoolean("Picture_Has_Correct_Location", false);
}
switch (errorCode) {
@ -196,10 +226,10 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
break;
case FILE_NAME_EXISTS:
Timber.d("Trying to show duplicate picture popup");
view.showDuplicatePicturePopup();
view.showDuplicatePicturePopup(uploadItem);
break;
default:
view.showBadImagePopup(errorCode);
view.showBadImagePopup(errorCode, uploadItem);
}
}

View file

@ -33,7 +33,7 @@ class u {
var imageProcessingService: ImageProcessingService? = null
@Mock
internal lateinit var uploadItem: UploadModel.UploadItem
internal lateinit var uploadItem: UploadItem
@Before
@Throws(Exception::class)

View file

@ -2,6 +2,7 @@ package fr.free.nrw.commons.upload
import com.nhaarman.mockitokotlin2.verify
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.repository.UploadRepository
import fr.free.nrw.commons.upload.license.MediaLicenseContract
import fr.free.nrw.commons.upload.license.MediaLicensePresenter
@ -24,13 +25,16 @@ import org.powermock.modules.junit4.PowerMockRunner
@PrepareForTest(Utils::class)
class MediaLicensePresenterTest {
@Mock
internal var repository: UploadRepository? = null
internal lateinit var repository: UploadRepository
@Mock
internal var view: MediaLicenseContract.View? = null
internal lateinit var defaultKvStore: JsonKvStore
@Mock
internal lateinit var view: MediaLicenseContract.View
@InjectMocks
var mediaLicensePresenter: MediaLicensePresenter? = null
lateinit var mediaLicensePresenter: MediaLicensePresenter
/**
* initial setup test environemnt
@ -39,7 +43,7 @@ class MediaLicensePresenterTest {
@Throws(Exception::class)
fun setUp() {
MockitoAnnotations.initMocks(this)
mediaLicensePresenter?.onAttachView(view)
mediaLicensePresenter.onAttachView(view)
PowerMockito.mockStatic(Utils::class.java)
PowerMockito.`when`(Utils.licenseNameFor(ArgumentMatchers.anyString())).thenReturn(1)
}
@ -50,9 +54,9 @@ class MediaLicensePresenterTest {
*/
@Test
fun getLicenseTest() {
mediaLicensePresenter?.getLicenses()
verify(view)?.setLicenses(ArgumentMatchers.anyList())
verify(view)?.setSelectedLicense(ArgumentMatchers.any())
mediaLicensePresenter.getLicenses()
verify(view).setLicenses(ArgumentMatchers.anyList())
verify(view).setSelectedLicense(ArgumentMatchers.any())
}
/**
@ -60,7 +64,7 @@ class MediaLicensePresenterTest {
*/
@Test
fun selectLicenseTest() {
mediaLicensePresenter?.selectLicense(ArgumentMatchers.anyString())
verify(view)?.updateLicenseSummary(ArgumentMatchers.any(), ArgumentMatchers.anyInt())
mediaLicensePresenter.selectLicense(ArgumentMatchers.anyString())
verify(view).updateLicenseSummary(ArgumentMatchers.any(), ArgumentMatchers.anyInt())
}
}
}

View file

@ -3,6 +3,7 @@ package fr.free.nrw.commons.upload
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.filepicker.UploadableFile
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.nearby.Place
import fr.free.nrw.commons.repository.UploadRepository
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailsContract
@ -41,16 +42,19 @@ class UploadMediaPresenterTest {
private lateinit var place: Place
@Mock
private lateinit var uploadItem: UploadModel.UploadItem
private lateinit var uploadItem: UploadItem
@Mock
private lateinit var uploadMediaDetails: List<UploadMediaDetail>
private lateinit var testObservableUploadItem: Observable<UploadModel.UploadItem>
private lateinit var testObservableUploadItem: Observable<UploadItem>
private lateinit var testSingleImageResult: Single<Int>
private lateinit var testScheduler: TestScheduler
@Mock
private lateinit var jsonKvStore: JsonKvStore
/**
* initial setup unit test environment
*/
@ -61,7 +65,8 @@ class UploadMediaPresenterTest {
testObservableUploadItem = Observable.just(uploadItem)
testSingleImageResult = Single.just(1)
testScheduler = TestScheduler()
uploadMediaPresenter = UploadMediaPresenter(repository, testScheduler, testScheduler)
uploadMediaPresenter = UploadMediaPresenter(repository,
jsonKvStore,testScheduler, testScheduler)
uploadMediaPresenter.onAttachView(view)
}
@ -81,7 +86,7 @@ class UploadMediaPresenterTest {
verify(view).showProgress(true)
testScheduler.triggerActions()
verify(view).onImageProcessed(
ArgumentMatchers.any(UploadModel.UploadItem::class.java),
ArgumentMatchers.any(UploadItem::class.java),
ArgumentMatchers.any(Place::class.java)
)
verify(view).showProgress(false)
@ -92,10 +97,11 @@ class UploadMediaPresenterTest {
*/
@Test
fun verifyImageQualityTest() {
whenever(repository.getImageQuality(ArgumentMatchers.any(UploadModel.UploadItem::class.java)))
whenever(repository.uploads).thenReturn(listOf(uploadItem))
whenever(repository.getImageQuality(uploadItem))
.thenReturn(testSingleImageResult)
whenever(uploadItem.imageQuality).thenReturn(ArgumentMatchers.anyInt())
uploadMediaPresenter.verifyImageQuality(uploadItem)
uploadMediaPresenter.verifyImageQuality(0)
verify(view).showProgress(true)
testScheduler.triggerActions()
verify(view).showProgress(false)
@ -107,21 +113,21 @@ class UploadMediaPresenterTest {
@Test
fun handleImageResult() {
//Positive case test
uploadMediaPresenter.handleImageResult(IMAGE_KEEP)
uploadMediaPresenter.handleImageResult(IMAGE_KEEP, uploadItem)
verify(view).onImageValidationSuccess()
//Duplicate file name
uploadMediaPresenter.handleImageResult(FILE_NAME_EXISTS)
verify(view).showDuplicatePicturePopup()
uploadMediaPresenter.handleImageResult(FILE_NAME_EXISTS, uploadItem)
verify(view).showDuplicatePicturePopup(uploadItem)
//Empty Caption test
uploadMediaPresenter.handleImageResult(EMPTY_CAPTION)
uploadMediaPresenter.handleImageResult(EMPTY_CAPTION, uploadItem)
verify(view).showMessage(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())
//Bad Picture test
//Empty Caption test
uploadMediaPresenter.handleImageResult(-7)
verify(view)?.showBadImagePopup(ArgumentMatchers.anyInt())
uploadMediaPresenter.handleImageResult(-7, uploadItem)
verify(view)?.showBadImagePopup(ArgumentMatchers.anyInt(), eq(uploadItem))
}
@ -138,7 +144,6 @@ class UploadMediaPresenterTest {
testScheduler.triggerActions()
verify(view).showProgress(true)
verify(view).onImageValidationSuccess()
uploadMediaPresenter.setUploadItem(0, uploadItem)
}
}
@ -155,7 +160,6 @@ class UploadMediaPresenterTest {
testScheduler.triggerActions()
verify(view).showProgress(true)
verify(view).onImageValidationSuccess()
uploadMediaPresenter.setUploadItem(0, uploadItem)
}
}
@ -164,12 +168,13 @@ class UploadMediaPresenterTest {
*/
@Test
fun fetchPreviousImageAndTitleTestPositive() {
whenever(repository.uploads).thenReturn(listOf(uploadItem))
whenever(repository.getPreviousUploadItem(ArgumentMatchers.anyInt()))
.thenReturn(uploadItem)
whenever(uploadItem.uploadMediaDetails).thenReturn(uploadMediaDetails)
whenever(uploadItem.uploadMediaDetails).thenReturn(listOf())
uploadMediaPresenter.fetchPreviousTitleAndDescription(0)
verify(view).setCaptionsAndDescriptions(ArgumentMatchers.any())
verify(view).updateMediaDetails(ArgumentMatchers.any())
}
/**
@ -188,9 +193,9 @@ class UploadMediaPresenterTest {
*/
@Test
fun handleBadImageBaseTestInvalidLocation() {
uploadMediaPresenter.handleBadImage(8)
verify(repository).saveValue(ArgumentMatchers.anyString(), eq(false))
verify(view).showBadImagePopup(8)
uploadMediaPresenter.handleBadImage(8, uploadItem)
verify(jsonKvStore).putBoolean(ArgumentMatchers.anyString(), eq(false))
verify(view).showBadImagePopup(8, uploadItem)
}
/**
@ -198,7 +203,7 @@ class UploadMediaPresenterTest {
*/
@Test
fun handleBadImageBaseTestEmptyTitle() {
uploadMediaPresenter.handleBadImage(-3)
uploadMediaPresenter.handleBadImage(-3, uploadItem)
verify(view).showMessage(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())
}
@ -207,8 +212,8 @@ class UploadMediaPresenterTest {
*/
@Test
fun handleBadImageBaseTestFileNameExists() {
uploadMediaPresenter.handleBadImage(-4)
verify(view).showDuplicatePicturePopup()
uploadMediaPresenter.handleBadImage(-4, uploadItem)
verify(view).showDuplicatePicturePopup(uploadItem)
}
@ -222,13 +227,4 @@ class UploadMediaPresenterTest {
verify(view).showSimilarImageFragment("original", "possible", similar)
}
/**
* Test set upload item
*/
@Test
fun setUploadItemTest() {
uploadMediaPresenter.setUploadItem(0, uploadItem)
verify(repository).updateUploadItem(0, uploadItem)
}
}