mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
* Initial changes to the flow, merged conflicts * Major changes to flow and logic * Final major changes to the flow and merged conflicts * Minor changes to thumbnail flow and merge conflicts * Fixed ImageProcessingServiceTest * Removed unnecessary file * Some code cleanup and fixed UploadRepositoryUnitTest * Minor javadoc changes and null checks * Fixed UMDFragmentUnitTest * Fixed and added new tests in UploadMediaPresenterTest * Optimised code for no connection cases and minor code cleanup * Minor bug fix * Fixed minor bug * Fixed a failing unit test * Removed values-yue-hant * Update UploadRepository.java --------- Co-authored-by: Nicolas Raoul <nicolas.raoul@gmail.com>
This commit is contained in:
parent
16960a369a
commit
42641644cb
13 changed files with 588 additions and 266 deletions
|
|
@ -196,13 +196,23 @@ public class UploadRepository {
|
||||||
/**
|
/**
|
||||||
* query the RemoteDataSource for image quality
|
* query the RemoteDataSource for image quality
|
||||||
*
|
*
|
||||||
* @param uploadItem
|
* @param uploadItem UploadItem whose caption is to be checked
|
||||||
* @return
|
* @return Quality of UploadItem
|
||||||
*/
|
*/
|
||||||
public Single<Integer> getImageQuality(UploadItem uploadItem, LatLng location) {
|
public Single<Integer> getImageQuality(UploadItem uploadItem, LatLng location) {
|
||||||
return uploadModel.getImageQuality(uploadItem, location);
|
return uploadModel.getImageQuality(uploadItem, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* query the RemoteDataSource for caption quality
|
||||||
|
*
|
||||||
|
* @param uploadItem UploadItem whose caption is to be checked
|
||||||
|
* @return Quality of caption of the UploadItem
|
||||||
|
*/
|
||||||
|
public Single<Integer> getCaptionQuality(UploadItem uploadItem) {
|
||||||
|
return uploadModel.getCaptionQuality(uploadItem);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* asks the LocalDataSource to delete the file with the given file path
|
* asks the LocalDataSource to delete the file with the given file path
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@ package fr.free.nrw.commons.upload;
|
||||||
|
|
||||||
import static fr.free.nrw.commons.utils.ImageUtils.EMPTY_CAPTION;
|
import static fr.free.nrw.commons.utils.ImageUtils.EMPTY_CAPTION;
|
||||||
import static fr.free.nrw.commons.utils.ImageUtils.FILE_NAME_EXISTS;
|
import static fr.free.nrw.commons.utils.ImageUtils.FILE_NAME_EXISTS;
|
||||||
|
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_DUPLICATE;
|
||||||
|
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_KEEP;
|
||||||
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK;
|
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
import fr.free.nrw.commons.media.MediaClient;
|
import fr.free.nrw.commons.media.MediaClient;
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
import fr.free.nrw.commons.nearby.Place;
|
||||||
import fr.free.nrw.commons.utils.ImageUtils;
|
|
||||||
import fr.free.nrw.commons.utils.ImageUtilsWrapper;
|
import fr.free.nrw.commons.utils.ImageUtilsWrapper;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
@ -45,13 +46,17 @@ public class ImageProcessingService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check image quality before upload - checks duplicate image - checks dark image - checks
|
* Check image quality before upload - checks duplicate image - checks dark image - checks
|
||||||
* geolocation for image - check for valid title
|
* geolocation for image
|
||||||
|
*
|
||||||
|
* @param uploadItem UploadItem whose quality is to be checked
|
||||||
|
* @param inAppPictureLocation In app picture location (if any)
|
||||||
|
* @return Quality of UploadItem
|
||||||
*/
|
*/
|
||||||
Single<Integer> validateImage(UploadItem uploadItem, LatLng inAppPictureLocation) {
|
Single<Integer> validateImage(UploadItem uploadItem, LatLng inAppPictureLocation) {
|
||||||
int currentImageQuality = uploadItem.getImageQuality();
|
int currentImageQuality = uploadItem.getImageQuality();
|
||||||
Timber.d("Current image quality is %d", currentImageQuality);
|
Timber.d("Current image quality is %d", currentImageQuality);
|
||||||
if (currentImageQuality == ImageUtils.IMAGE_KEEP) {
|
if (currentImageQuality == IMAGE_KEEP || currentImageQuality == IMAGE_OK) {
|
||||||
return Single.just(ImageUtils.IMAGE_OK);
|
return Single.just(IMAGE_OK);
|
||||||
}
|
}
|
||||||
Timber.d("Checking the validity of image");
|
Timber.d("Checking the validity of image");
|
||||||
String filePath = uploadItem.getMediaUri().getPath();
|
String filePath = uploadItem.getMediaUri().getPath();
|
||||||
|
|
@ -60,18 +65,34 @@ public class ImageProcessingService {
|
||||||
checkDuplicateImage(filePath),
|
checkDuplicateImage(filePath),
|
||||||
checkImageGeoLocation(uploadItem.getPlace(), filePath, inAppPictureLocation),
|
checkImageGeoLocation(uploadItem.getPlace(), filePath, inAppPictureLocation),
|
||||||
checkDarkImage(filePath),
|
checkDarkImage(filePath),
|
||||||
validateItemTitle(uploadItem),
|
|
||||||
checkFBMD(filePath),
|
checkFBMD(filePath),
|
||||||
checkEXIF(filePath),
|
checkEXIF(filePath),
|
||||||
(duplicateImage, wrongGeoLocation, darkImage, itemTitle, fbmd, exif) -> {
|
(duplicateImage, wrongGeoLocation, darkImage, fbmd, exif) -> {
|
||||||
Timber.d("duplicate: %d, geo: %d, dark: %d, title: %d" + "fbmd:" + fbmd + "exif:"
|
Timber.d("duplicate: %d, geo: %d, dark: %d" + "fbmd:" + fbmd + "exif:"
|
||||||
+ exif,
|
+ exif,
|
||||||
duplicateImage, wrongGeoLocation, darkImage, itemTitle);
|
duplicateImage, wrongGeoLocation, darkImage);
|
||||||
return duplicateImage | wrongGeoLocation | darkImage | itemTitle | fbmd | exif;
|
return duplicateImage | wrongGeoLocation | darkImage | fbmd | exif;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks caption of the given UploadItem
|
||||||
|
*
|
||||||
|
* @param uploadItem UploadItem whose caption is to be verified
|
||||||
|
* @return Quality of caption of the UploadItem
|
||||||
|
*/
|
||||||
|
Single<Integer> validateCaption(UploadItem uploadItem) {
|
||||||
|
int currentImageQuality = uploadItem.getImageQuality();
|
||||||
|
Timber.d("Current image quality is %d", currentImageQuality);
|
||||||
|
if (currentImageQuality == IMAGE_KEEP) {
|
||||||
|
return Single.just(IMAGE_OK);
|
||||||
|
}
|
||||||
|
Timber.d("Checking the validity of caption");
|
||||||
|
|
||||||
|
return validateItemTitle(uploadItem);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We want to discourage users from uploading images to Commons that were taken from Facebook.
|
* We want to discourage users from uploading images to Commons that were taken from Facebook.
|
||||||
* This attempts to detect whether an image was downloaded from Facebook by heuristically
|
* This attempts to detect whether an image was downloaded from Facebook by heuristically
|
||||||
|
|
@ -126,7 +147,7 @@ public class ImageProcessingService {
|
||||||
.flatMap(mediaClient::checkFileExistsUsingSha)
|
.flatMap(mediaClient::checkFileExistsUsingSha)
|
||||||
.map(b -> {
|
.map(b -> {
|
||||||
Timber.d("Result for duplicate image %s", b);
|
Timber.d("Result for duplicate image %s", b);
|
||||||
return b ? ImageUtils.IMAGE_DUPLICATE : ImageUtils.IMAGE_OK;
|
return b ? IMAGE_DUPLICATE : IMAGE_OK;
|
||||||
})
|
})
|
||||||
.subscribeOn(Schedulers.io());
|
.subscribeOn(Schedulers.io());
|
||||||
}
|
}
|
||||||
|
|
@ -152,13 +173,13 @@ public class ImageProcessingService {
|
||||||
private Single<Integer> checkImageGeoLocation(Place place, String filePath, LatLng inAppPictureLocation) {
|
private Single<Integer> checkImageGeoLocation(Place place, String filePath, LatLng inAppPictureLocation) {
|
||||||
Timber.d("Checking for image geolocation %s", filePath);
|
Timber.d("Checking for image geolocation %s", filePath);
|
||||||
if (place == null || StringUtils.isBlank(place.getWikiDataEntityId())) {
|
if (place == null || StringUtils.isBlank(place.getWikiDataEntityId())) {
|
||||||
return Single.just(ImageUtils.IMAGE_OK);
|
return Single.just(IMAGE_OK);
|
||||||
}
|
}
|
||||||
return Single.fromCallable(() -> filePath)
|
return Single.fromCallable(() -> filePath)
|
||||||
.flatMap(path -> Single.just(fileUtilsWrapper.getGeolocationOfFile(path, inAppPictureLocation)))
|
.flatMap(path -> Single.just(fileUtilsWrapper.getGeolocationOfFile(path, inAppPictureLocation)))
|
||||||
.flatMap(geoLocation -> {
|
.flatMap(geoLocation -> {
|
||||||
if (StringUtils.isBlank(geoLocation)) {
|
if (StringUtils.isBlank(geoLocation)) {
|
||||||
return Single.just(ImageUtils.IMAGE_OK);
|
return Single.just(IMAGE_OK);
|
||||||
}
|
}
|
||||||
return imageUtilsWrapper
|
return imageUtilsWrapper
|
||||||
.checkImageGeolocationIsDifferent(geoLocation, place.getLocation());
|
.checkImageGeolocationIsDifferent(geoLocation, place.getLocation());
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ import fr.free.nrw.commons.upload.depicts.DepictsFragment;
|
||||||
import fr.free.nrw.commons.upload.license.MediaLicenseFragment;
|
import fr.free.nrw.commons.upload.license.MediaLicenseFragment;
|
||||||
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment;
|
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment;
|
||||||
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.UploadMediaDetailFragmentCallback;
|
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.UploadMediaDetailFragmentCallback;
|
||||||
|
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaPresenter;
|
||||||
import fr.free.nrw.commons.upload.worker.WorkRequestHelper;
|
import fr.free.nrw.commons.upload.worker.WorkRequestHelper;
|
||||||
import fr.free.nrw.commons.utils.DialogUtil;
|
import fr.free.nrw.commons.utils.DialogUtil;
|
||||||
import fr.free.nrw.commons.utils.PermissionUtils;
|
import fr.free.nrw.commons.utils.PermissionUtils;
|
||||||
|
|
@ -96,7 +97,7 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
private DepictsFragment depictsFragment;
|
private DepictsFragment depictsFragment;
|
||||||
private MediaLicenseFragment mediaLicenseFragment;
|
private MediaLicenseFragment mediaLicenseFragment;
|
||||||
private ThumbnailsAdapter thumbnailsAdapter;
|
private ThumbnailsAdapter thumbnailsAdapter;
|
||||||
|
BasicKvStore store;
|
||||||
private Place place;
|
private Place place;
|
||||||
private LatLng prevLocation;
|
private LatLng prevLocation;
|
||||||
private LatLng currLocation;
|
private LatLng currLocation;
|
||||||
|
|
@ -140,6 +141,9 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
*/
|
*/
|
||||||
private boolean isFragmentsSaved = false;
|
private boolean isFragmentsSaved = false;
|
||||||
|
|
||||||
|
public static final String keyForCurrentUploadImagesSize = "CurrentUploadImagesSize";
|
||||||
|
public static final String storeNameForCurrentUploadImagesSize = "CurrentUploadImageQualities";
|
||||||
|
|
||||||
private ActivityUploadBinding binding;
|
private ActivityUploadBinding binding;
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
|
|
@ -179,7 +183,10 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
}
|
}
|
||||||
locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER);
|
locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER);
|
||||||
locationManager.requestLocationUpdatesFromProvider(LocationManager.NETWORK_PROVIDER);
|
locationManager.requestLocationUpdatesFromProvider(LocationManager.NETWORK_PROVIDER);
|
||||||
|
store = new BasicKvStore(this, storeNameForCurrentUploadImagesSize);
|
||||||
|
store.clearAll();
|
||||||
checkStoragePermissions();
|
checkStoragePermissions();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
|
|
@ -470,6 +477,8 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
if (uploadableFiles.size() > 3
|
if (uploadableFiles.size() > 3
|
||||||
&& !defaultKvStore.getBoolean("hasAlreadyLaunchedBigMultiupload")) {
|
&& !defaultKvStore.getBoolean("hasAlreadyLaunchedBigMultiupload")) {
|
||||||
|
// When battery-optimisation dialog is shown don't show the image quality dialog
|
||||||
|
UploadMediaPresenter.isBatteryDialogShowing = true;
|
||||||
DialogUtil.showAlertDialog(
|
DialogUtil.showAlertDialog(
|
||||||
this,
|
this,
|
||||||
getString(R.string.unrestricted_battery_mode),
|
getString(R.string.unrestricted_battery_mode),
|
||||||
|
|
@ -490,8 +499,15 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
Intent batteryOptimisationSettingsIntent = new Intent(
|
Intent batteryOptimisationSettingsIntent = new Intent(
|
||||||
Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
|
Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
|
||||||
startActivity(batteryOptimisationSettingsIntent);
|
startActivity(batteryOptimisationSettingsIntent);
|
||||||
|
// calling checkImageQuality after battery dialog is interacted with
|
||||||
|
// so that 2 dialogs do not pop up simultaneously
|
||||||
|
presenter.checkImageQuality(0);
|
||||||
|
UploadMediaPresenter.isBatteryDialogShowing = false;
|
||||||
},
|
},
|
||||||
() -> {}
|
() -> {
|
||||||
|
presenter.checkImageQuality(0);
|
||||||
|
UploadMediaPresenter.isBatteryDialogShowing = false;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
defaultKvStore.putBoolean("hasAlreadyLaunchedBigMultiupload", true);
|
defaultKvStore.putBoolean("hasAlreadyLaunchedBigMultiupload", true);
|
||||||
}
|
}
|
||||||
|
|
@ -525,6 +541,8 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
UploadMediaDetailFragmentCallback uploadMediaDetailFragmentCallback = new UploadMediaDetailFragmentCallback() {
|
UploadMediaDetailFragmentCallback uploadMediaDetailFragmentCallback = new UploadMediaDetailFragmentCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void deletePictureAtIndex(int index) {
|
public void deletePictureAtIndex(int index) {
|
||||||
|
store.putInt(keyForCurrentUploadImagesSize,
|
||||||
|
(store.getInt(keyForCurrentUploadImagesSize) - 1));
|
||||||
presenter.deletePictureAtIndex(index);
|
presenter.deletePictureAtIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -668,6 +686,8 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
binding.vpUpload.setOffscreenPageLimit(fragments.size());
|
binding.vpUpload.setOffscreenPageLimit(fragments.size());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// Saving size of uploadableFiles
|
||||||
|
store.putInt(keyForCurrentUploadImagesSize, uploadableFiles.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -788,6 +808,10 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
fragments.get(index + 1).onBecameVisible();
|
fragments.get(index + 1).onBecameVisible();
|
||||||
((LinearLayoutManager) binding.rvThumbnails.getLayoutManager())
|
((LinearLayoutManager) binding.rvThumbnails.getLayoutManager())
|
||||||
.scrollToPositionWithOffset((index > 0) ? index - 1 : 0, 0);
|
.scrollToPositionWithOffset((index > 0) ? index - 1 : 0, 0);
|
||||||
|
if (index < fragments.size() - 4) {
|
||||||
|
// check image quality if next image exists
|
||||||
|
presenter.checkImageQuality(index + 1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
presenter.handleSubmit();
|
presenter.handleSubmit();
|
||||||
}
|
}
|
||||||
|
|
@ -800,7 +824,11 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
fragments.get(index - 1).onBecameVisible();
|
fragments.get(index - 1).onBecameVisible();
|
||||||
((LinearLayoutManager) binding.rvThumbnails.getLayoutManager())
|
((LinearLayoutManager) binding.rvThumbnails.getLayoutManager())
|
||||||
.scrollToPositionWithOffset((index > 3) ? index-2 : 0, 0);
|
.scrollToPositionWithOffset((index > 3) ? index-2 : 0, 0);
|
||||||
binding.llContainerTopCard.setVisibility(View.VISIBLE);
|
if ((index != 1) && ((index - 1) < uploadableFiles.size())) {
|
||||||
|
// Shows the top card if it was hidden because of the last image being deleted and
|
||||||
|
// now the user has hit previous button to go back to the media details
|
||||||
|
showHideTopCard(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -854,6 +882,8 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
// Resetting all values in store by clearing them
|
||||||
|
store.clearAll();
|
||||||
presenter.onDetachView();
|
presenter.onDetachView();
|
||||||
compositeDisposable.clear();
|
compositeDisposable.clear();
|
||||||
fragments = null;
|
fragments = null;
|
||||||
|
|
|
||||||
|
|
@ -64,5 +64,12 @@ public interface UploadContract {
|
||||||
void handleSubmit();
|
void handleSubmit();
|
||||||
|
|
||||||
void deletePictureAtIndex(int index);
|
void deletePictureAtIndex(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls checkImageQuality of UploadMediaPresenter to check image quality of next image
|
||||||
|
*
|
||||||
|
* @param uploadItemIndex Index of next image, whose quality is to be checked
|
||||||
|
*/
|
||||||
|
void checkImageQuality(int uploadItemIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,10 +92,27 @@ public class UploadModel {
|
||||||
createAndAddUploadItem(uploadableFile, place, similarImageInterface, inAppPictureLocation));
|
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<Integer> getImageQuality(final UploadItem uploadItem, LatLng inAppPictureLocation) {
|
public Single<Integer> getImageQuality(final UploadItem uploadItem, LatLng inAppPictureLocation) {
|
||||||
return imageProcessingService.validateImage(uploadItem, inAppPictureLocation);
|
return imageProcessingService.validateImage(uploadItem, inAppPictureLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<Integer> getCaptionQuality(final UploadItem uploadItem) {
|
||||||
|
return imageProcessingService.validateCaption(uploadItem);
|
||||||
|
}
|
||||||
|
|
||||||
private UploadItem createAndAddUploadItem(final UploadableFile uploadableFile,
|
private UploadItem createAndAddUploadItem(final UploadableFile uploadableFile,
|
||||||
final Place place,
|
final Place place,
|
||||||
final SimilarImageInterface similarImageInterface,
|
final SimilarImageInterface similarImageInterface,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import fr.free.nrw.commons.contributions.Contribution;
|
||||||
import fr.free.nrw.commons.filepicker.UploadableFile;
|
import fr.free.nrw.commons.filepicker.UploadableFile;
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.repository.UploadRepository;
|
import fr.free.nrw.commons.repository.UploadRepository;
|
||||||
|
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailsContract;
|
||||||
import io.reactivex.Observer;
|
import io.reactivex.Observer;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
|
|
@ -30,6 +31,8 @@ public class UploadPresenter implements UploadContract.UserActionListener {
|
||||||
private final UploadRepository repository;
|
private final UploadRepository repository;
|
||||||
private final JsonKvStore defaultKvStore;
|
private final JsonKvStore defaultKvStore;
|
||||||
private UploadContract.View view = DUMMY;
|
private UploadContract.View view = DUMMY;
|
||||||
|
@Inject
|
||||||
|
UploadMediaDetailsContract.UserActionListener presenter;
|
||||||
|
|
||||||
private CompositeDisposable compositeDisposable;
|
private CompositeDisposable compositeDisposable;
|
||||||
public static final String COUNTER_OF_CONSECUTIVE_UPLOADS_WITHOUT_COORDINATES
|
public static final String COUNTER_OF_CONSECUTIVE_UPLOADS_WITHOUT_COORDINATES
|
||||||
|
|
@ -135,9 +138,26 @@ public class UploadPresenter implements UploadContract.UserActionListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls checkImageQuality of UploadMediaPresenter to check image quality of next image
|
||||||
|
*
|
||||||
|
* @param uploadItemIndex Index of next image, whose quality is to be checked
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void checkImageQuality(int uploadItemIndex) {
|
||||||
|
UploadItem uploadItem = repository.getUploadItem(uploadItemIndex);
|
||||||
|
presenter.checkImageQuality(uploadItem, uploadItemIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deletePictureAtIndex(int index) {
|
public void deletePictureAtIndex(int index) {
|
||||||
List<UploadableFile> uploadableFiles = view.getUploadableFiles();
|
List<UploadableFile> uploadableFiles = view.getUploadableFiles();
|
||||||
|
if (index == uploadableFiles.size() - 1) {
|
||||||
|
// If the next fragment to be shown is not one of the MediaDetailsFragment
|
||||||
|
// lets hide the top card so that it doesn't appear on the other fragments
|
||||||
|
view.showHideTopCard(false);
|
||||||
|
}
|
||||||
view.setImageCancelled(true);
|
view.setImageCancelled(true);
|
||||||
repository.deletePicture(uploadableFiles.get(index).getFilePath());
|
repository.deletePicture(uploadableFiles.get(index).getFilePath());
|
||||||
if (uploadableFiles.size() == 1) {
|
if (uploadableFiles.size() == 1) {
|
||||||
|
|
@ -145,7 +165,15 @@ public class UploadPresenter implements UploadContract.UserActionListener {
|
||||||
view.finish();
|
view.finish();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
if (presenter != null) {
|
||||||
|
presenter.updateImageQualitiesJSON(uploadableFiles.size(), index);
|
||||||
|
}
|
||||||
view.onUploadMediaDeleted(index);
|
view.onUploadMediaDeleted(index);
|
||||||
|
if (!(index == uploadableFiles.size()) && index != 0) {
|
||||||
|
// if the deleted image was not the last item to be uploaded, check quality of next
|
||||||
|
UploadItem uploadItem = repository.getUploadItem(index);
|
||||||
|
presenter.checkImageQuality(uploadItem, index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (uploadableFiles.size() < 2) {
|
if (uploadableFiles.size() < 2) {
|
||||||
view.showHideTopCard(false);
|
view.showHideTopCard(false);
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,9 @@ package fr.free.nrw.commons.upload.mediaDetails;
|
||||||
|
|
||||||
import static android.app.Activity.RESULT_OK;
|
import static android.app.Activity.RESULT_OK;
|
||||||
import static fr.free.nrw.commons.utils.ActivityUtils.startActivityWithFlags;
|
import static fr.free.nrw.commons.utils.ActivityUtils.startActivityWithFlags;
|
||||||
import static fr.free.nrw.commons.utils.ImageUtils.FILE_NAME_EXISTS;
|
|
||||||
import static fr.free.nrw.commons.utils.ImageUtils.getErrorMessageForResult;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
@ -44,6 +43,7 @@ import fr.free.nrw.commons.upload.UploadMediaDetail;
|
||||||
import fr.free.nrw.commons.upload.UploadMediaDetailAdapter;
|
import fr.free.nrw.commons.upload.UploadMediaDetailAdapter;
|
||||||
import fr.free.nrw.commons.utils.DialogUtil;
|
import fr.free.nrw.commons.utils.DialogUtil;
|
||||||
import fr.free.nrw.commons.utils.ImageUtils;
|
import fr.free.nrw.commons.utils.ImageUtils;
|
||||||
|
import fr.free.nrw.commons.utils.NetworkUtils;
|
||||||
import fr.free.nrw.commons.utils.ViewUtil;
|
import fr.free.nrw.commons.utils.ViewUtil;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -52,7 +52,6 @@ import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
|
|
@ -62,6 +61,10 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
private static final int REQUEST_CODE_FOR_EDIT_ACTIVITY = 1212;
|
private static final int REQUEST_CODE_FOR_EDIT_ACTIVITY = 1212;
|
||||||
private static final int REQUEST_CODE_FOR_VOICE_INPUT = 1213;
|
private static final int REQUEST_CODE_FOR_VOICE_INPUT = 1213;
|
||||||
|
|
||||||
|
public static Activity activity ;
|
||||||
|
|
||||||
|
private int indexOfFragment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A key for applicationKvStore. By this key we can retrieve the location of last UploadItem ex.
|
* A key for applicationKvStore. By this key we can retrieve the location of last UploadItem ex.
|
||||||
* 12.3433,54.78897 from applicationKvStore.
|
* 12.3433,54.78897 from applicationKvStore.
|
||||||
|
|
@ -119,12 +122,17 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
*/
|
*/
|
||||||
private UploadItem editableUploadItem;
|
private UploadItem editableUploadItem;
|
||||||
|
|
||||||
|
private BasicKvStore basicKvStore;
|
||||||
|
|
||||||
|
private final String keyForShowingAlertDialog = "isNoNetworkAlertDialogShowing";
|
||||||
|
|
||||||
private UploadMediaDetailFragmentCallback callback;
|
private UploadMediaDetailFragmentCallback callback;
|
||||||
|
|
||||||
private FragmentUploadMediaDetailFragmentBinding binding;
|
private FragmentUploadMediaDetailFragmentBinding binding;
|
||||||
|
|
||||||
public void setCallback(UploadMediaDetailFragmentCallback callback) {
|
public void setCallback(UploadMediaDetailFragmentCallback callback) {
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
UploadMediaPresenter.presenterCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -160,24 +168,38 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
|
activity = getActivity();
|
||||||
|
basicKvStore = new BasicKvStore(activity, "CurrentUploadImageQualities");
|
||||||
|
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
|
indexOfFragment = callback.getIndexInViewFlipper(this);
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(savedInstanceState!=null){
|
if(savedInstanceState!=null){
|
||||||
if(uploadMediaDetailAdapter.getItems().size()==0 && callback != null){
|
if(uploadMediaDetailAdapter.getItems().size()==0 && callback != null){
|
||||||
uploadMediaDetailAdapter.setItems(savedInstanceState.getParcelableArrayList(UPLOAD_MEDIA_DETAILS));
|
uploadMediaDetailAdapter.setItems(savedInstanceState.getParcelableArrayList(UPLOAD_MEDIA_DETAILS));
|
||||||
presenter.setUploadMediaDetails(uploadMediaDetailAdapter.getItems(), callback.getIndexInViewFlipper(this));
|
presenter.setUploadMediaDetails(uploadMediaDetailAdapter.getItems(),
|
||||||
|
indexOfFragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(!presenter.getImageQuality(indexOfFragment, inAppPictureLocation, getActivity())) {
|
||||||
|
startActivityWithFlags(
|
||||||
|
getActivity(), MainActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP,
|
||||||
|
Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
if (binding == null) {
|
if (binding == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
binding.tvTitle.setText(getString(R.string.step_count, callback.getIndexInViewFlipper(this) + 1,
|
binding.tvTitle.setText(getString(R.string.step_count, (indexOfFragment + 1),
|
||||||
callback.getTotalNumberOfSteps(), getString(R.string.media_detail_step_title)));
|
callback.getTotalNumberOfSteps(), getString(R.string.media_detail_step_title)));
|
||||||
binding.tooltip.setOnClickListener(
|
binding.tooltip.setOnClickListener(
|
||||||
v -> showInfoAlert(R.string.media_detail_step_title, R.string.media_details_tooltip));
|
v -> showInfoAlert(R.string.media_detail_step_title, R.string.media_details_tooltip));
|
||||||
|
|
@ -185,7 +207,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
presenter.receiveImage(uploadableFile, place, inAppPictureLocation);
|
presenter.receiveImage(uploadableFile, place, inAppPictureLocation);
|
||||||
initRecyclerView();
|
initRecyclerView();
|
||||||
|
|
||||||
if (callback.getIndexInViewFlipper(this) == 0) {
|
if (indexOfFragment == 0) {
|
||||||
binding.btnPrevious.setEnabled(false);
|
binding.btnPrevious.setEnabled(false);
|
||||||
binding.btnPrevious.setAlpha(0.5f);
|
binding.btnPrevious.setAlpha(0.5f);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -208,7 +230,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
}
|
}
|
||||||
|
|
||||||
//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
|
||||||
if (callback.getIndexInViewFlipper(this) == callback.getTotalNumberOfSteps() - 4) {
|
if (indexOfFragment == callback.getTotalNumberOfSteps() - 4) {
|
||||||
binding.btnCopySubsequentMedia.setVisibility(View.GONE);
|
binding.btnCopySubsequentMedia.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
binding.btnCopySubsequentMedia.setVisibility(View.VISIBLE);
|
binding.btnCopySubsequentMedia.setVisibility(View.VISIBLE);
|
||||||
|
|
@ -273,23 +295,18 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean isValidUploads = presenter.verifyImageQuality(callback.getIndexInViewFlipper(this), inAppPictureLocation);
|
presenter.displayLocDialog(indexOfFragment, inAppPictureLocation);
|
||||||
if (!isValidUploads) {
|
|
||||||
startActivityWithFlags(
|
|
||||||
getActivity(), MainActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP,
|
|
||||||
Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPreviousButtonClicked() {
|
public void onPreviousButtonClicked() {
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callback.onPreviousButtonClicked(callback.getIndexInViewFlipper(this));
|
callback.onPreviousButtonClicked(indexOfFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onEditButtonClicked() {
|
public void onEditButtonClicked() {
|
||||||
presenter.onEditButtonClicked(callback.getIndexInViewFlipper(this));
|
presenter.onEditButtonClicked(indexOfFragment);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void showSimilarImageFragment(String originalFilePath, String possibleFilePath,
|
public void showSimilarImageFragment(String originalFilePath, String possibleFilePath,
|
||||||
|
|
@ -302,7 +319,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
public void onPositiveResponse() {
|
public void onPositiveResponse() {
|
||||||
Timber.d("positive response from similar image fragment");
|
Timber.d("positive response from similar image fragment");
|
||||||
presenter.useSimilarPictureCoordinates(similarImageCoordinates,
|
presenter.useSimilarPictureCoordinates(similarImageCoordinates,
|
||||||
callback.getIndexInViewFlipper(UploadMediaDetailFragment.this));
|
indexOfFragment);
|
||||||
|
|
||||||
// set the description text when user selects to use coordinate from the other image
|
// set the description text when user selects to use coordinate from the other image
|
||||||
// which was taken within 120s
|
// which was taken within 120s
|
||||||
|
|
@ -346,13 +363,13 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (callback.getIndexInViewFlipper(this) == 0) {
|
if (indexOfFragment == 0) {
|
||||||
if (UploadActivity.nearbyPopupAnswers.containsKey(nearbyPlace)) {
|
if (UploadActivity.nearbyPopupAnswers.containsKey(nearbyPlace)) {
|
||||||
final boolean response = UploadActivity.nearbyPopupAnswers.get(nearbyPlace);
|
final boolean response = UploadActivity.nearbyPopupAnswers.get(nearbyPlace);
|
||||||
if (response) {
|
if (response) {
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
presenter.onUserConfirmedUploadIsOfPlace(nearbyPlace,
|
presenter.onUserConfirmedUploadIsOfPlace(nearbyPlace,
|
||||||
callback.getIndexInViewFlipper(this));
|
indexOfFragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -379,7 +396,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
place.getName()),
|
place.getName()),
|
||||||
() -> {
|
() -> {
|
||||||
UploadActivity.nearbyPopupAnswers.put(place, true);
|
UploadActivity.nearbyPopupAnswers.put(place, true);
|
||||||
presenter.onUserConfirmedUploadIsOfPlace(place, callback.getIndexInViewFlipper(this));
|
presenter.onUserConfirmedUploadIsOfPlace(place, indexOfFragment);
|
||||||
},
|
},
|
||||||
() -> {
|
() -> {
|
||||||
UploadActivity.nearbyPopupAnswers.put(place, false);
|
UploadActivity.nearbyPopupAnswers.put(place, false);
|
||||||
|
|
@ -400,7 +417,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callback.onNextButtonClicked(callback.getIndexInViewFlipper(this));
|
callback.onNextButtonClicked(indexOfFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -412,15 +429,13 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
presenter.fetchTitleAndDescription(callback.getIndexInViewFlipper(this));
|
presenter.fetchTitleAndDescription(indexOfFragment);
|
||||||
if (showNearbyFound) {
|
if (showNearbyFound) {
|
||||||
if (UploadActivity.nearbyPopupAnswers.containsKey(nearbyPlace)) {
|
if (UploadActivity.nearbyPopupAnswers.containsKey(nearbyPlace)) {
|
||||||
final boolean response = UploadActivity.nearbyPopupAnswers.get(nearbyPlace);
|
final boolean response = UploadActivity.nearbyPopupAnswers.get(nearbyPlace);
|
||||||
if (response) {
|
if (response) {
|
||||||
if (callback != null) {
|
|
||||||
presenter.onUserConfirmedUploadIsOfPlace(nearbyPlace,
|
presenter.onUserConfirmedUploadIsOfPlace(nearbyPlace,
|
||||||
callback.getIndexInViewFlipper(this));
|
indexOfFragment);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showNearbyPlaceFound(nearbyPlace);
|
showNearbyPlaceFound(nearbyPlace);
|
||||||
|
|
@ -466,51 +481,70 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
false);
|
false);
|
||||||
} else {
|
} else {
|
||||||
uploadItem.setImageQuality(ImageUtils.IMAGE_KEEP);
|
uploadItem.setImageQuality(ImageUtils.IMAGE_KEEP);
|
||||||
// Calling below, instead of onNextButtonClicked() to not show locationDialog twice
|
|
||||||
onImageValidationSuccess();
|
onImageValidationSuccess();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void showBadImagePopup(Integer errorCode,
|
* Shows a dialog alerting the user that internet connection is required for upload process
|
||||||
UploadItem uploadItem) {
|
* Does nothing if there is network connectivity and then the user presses okay
|
||||||
String errorMessageForResult = getErrorMessageForResult(getContext(), errorCode);
|
|
||||||
if (!StringUtils.isBlank(errorMessageForResult)) {
|
|
||||||
DialogUtil.showAlertDialog(getActivity(),
|
|
||||||
getString(R.string.upload_problem_image),
|
|
||||||
errorMessageForResult,
|
|
||||||
getString(R.string.upload),
|
|
||||||
getString(R.string.cancel),
|
|
||||||
() -> {
|
|
||||||
/*
|
|
||||||
User skipped the warning of low quality image, so we call
|
|
||||||
onImageValidationSuccess rather than onNextButtonClicked to avoid showing
|
|
||||||
other warning popups again.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// validate image only when same file name error does not occur
|
|
||||||
// show the same file name error if exists.
|
|
||||||
// If image with same file name exists check the bit in errorCode is set or not
|
|
||||||
if ((errorCode & FILE_NAME_EXISTS) != 0) {
|
|
||||||
Timber.d("Trying to show duplicate picture popup");
|
|
||||||
showDuplicatePicturePopup(uploadItem);
|
|
||||||
} else {
|
|
||||||
uploadItem.setImageQuality(ImageUtils.IMAGE_KEEP);
|
|
||||||
onImageValidationSuccess();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() -> deleteThisPicture()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
//If the error message is null, we will probably not show anything
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showConnectionErrorPopup() {
|
public void showConnectionErrorPopupForCaptionCheck() {
|
||||||
DialogUtil.showAlertDialog(getActivity(),
|
DialogUtil.showAlertDialog(getActivity(),
|
||||||
getString(R.string.upload_connection_error_alert_title),
|
getString(R.string.upload_connection_error_alert_title),
|
||||||
getString(R.string.upload_connection_error_alert_detail), getString(R.string.ok),
|
getString(R.string.upload_connection_error_alert_detail),
|
||||||
() -> {}, true);
|
getString(R.string.ok),
|
||||||
|
getString(R.string.cancel_upload),
|
||||||
|
() -> {
|
||||||
|
if (!NetworkUtils.isInternetConnectionEstablished(activity)) {
|
||||||
|
showConnectionErrorPopupForCaptionCheck();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
activity.finish();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a dialog alerting the user that internet connection is required for upload process
|
||||||
|
* Recalls UploadMediaPresenter.getImageQuality for all the next upload items,
|
||||||
|
* if there is network connectivity and then the user presses okay
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void showConnectionErrorPopup() {
|
||||||
|
try {
|
||||||
|
boolean FLAG_ALERT_DIALOG_SHOWING = basicKvStore.getBoolean(
|
||||||
|
keyForShowingAlertDialog, false);
|
||||||
|
if (!FLAG_ALERT_DIALOG_SHOWING) {
|
||||||
|
basicKvStore.putBoolean(keyForShowingAlertDialog, true);
|
||||||
|
DialogUtil.showAlertDialog(getActivity(),
|
||||||
|
getString(R.string.upload_connection_error_alert_title),
|
||||||
|
getString(R.string.upload_connection_error_alert_detail),
|
||||||
|
getString(R.string.ok),
|
||||||
|
getString(R.string.cancel_upload),
|
||||||
|
() -> {
|
||||||
|
basicKvStore.putBoolean(keyForShowingAlertDialog, false);
|
||||||
|
if (NetworkUtils.isInternetConnectionEstablished(activity)) {
|
||||||
|
int sizeOfUploads = basicKvStore.getInt(
|
||||||
|
UploadActivity.keyForCurrentUploadImagesSize);
|
||||||
|
for (int i = indexOfFragment; i < sizeOfUploads; i++) {
|
||||||
|
presenter.getImageQuality(i, inAppPictureLocation, activity);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showConnectionErrorPopup();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
basicKvStore.putBoolean(keyForShowingAlertDialog, false);
|
||||||
|
activity.finish();
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -622,9 +656,8 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
binding.backgroundImage.setImageURI(Uri.fromFile(new File(result)));
|
binding.backgroundImage.setImageURI(Uri.fromFile(new File(result)));
|
||||||
}
|
}
|
||||||
editableUploadItem.setContentUri(Uri.fromFile(new File(result)));
|
editableUploadItem.setContentUri(Uri.fromFile(new File(result)));
|
||||||
if (callback != null) {
|
callback.changeThumbnail(indexOfFragment,
|
||||||
callback.changeThumbnail(callback.getIndexInViewFlipper(this), result);
|
result);
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Timber.e(e);
|
Timber.e(e);
|
||||||
}
|
}
|
||||||
|
|
@ -711,13 +744,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
onSkipClicked);
|
onSkipClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteThisPicture() {
|
|
||||||
if (callback == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback.deletePictureAtIndex(callback.getIndexInViewFlipper(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
|
|
@ -745,7 +771,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
presenter.onMapIconClicked(callback.getIndexInViewFlipper(this));
|
presenter.onMapIconClicked(indexOfFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -781,10 +807,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
|
|
||||||
|
|
||||||
public void onButtonCopyTitleDescToSubsequentMedia(){
|
public void onButtonCopyTitleDescToSubsequentMedia(){
|
||||||
if (callback == null) {
|
presenter.copyTitleAndDescriptionToSubsequentMedia(indexOfFragment);
|
||||||
return;
|
|
||||||
}
|
|
||||||
presenter.copyTitleAndDescriptionToSubsequentMedia(callback.getIndexInViewFlipper(this));
|
|
||||||
Toast.makeText(getContext(), getResources().getString(R.string.copied_successfully), Toast.LENGTH_SHORT).show();
|
Toast.makeText(getContext(), getResources().getString(R.string.copied_successfully), Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.upload.mediaDetails;
|
package fr.free.nrw.commons.upload.mediaDetails;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import fr.free.nrw.commons.BasePresenter;
|
import fr.free.nrw.commons.BasePresenter;
|
||||||
import fr.free.nrw.commons.filepicker.UploadableFile;
|
import fr.free.nrw.commons.filepicker.UploadableFile;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
|
|
@ -31,10 +32,19 @@ public interface UploadMediaDetailsContract {
|
||||||
|
|
||||||
void showDuplicatePicturePopup(UploadItem uploadItem);
|
void showDuplicatePicturePopup(UploadItem uploadItem);
|
||||||
|
|
||||||
void showBadImagePopup(Integer errorCode, UploadItem uploadItem);
|
/**
|
||||||
|
* Shows a dialog alerting the user that internet connection is required for upload process
|
||||||
|
* Recalls UploadMediaPresenter.getImageQuality for all the next upload items,
|
||||||
|
* if there is network connectivity and then the user presses okay
|
||||||
|
*/
|
||||||
void showConnectionErrorPopup();
|
void showConnectionErrorPopup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a dialog alerting the user that internet connection is required for upload process
|
||||||
|
* Does nothing if there is network connectivity and then the user presses okay
|
||||||
|
*/
|
||||||
|
void showConnectionErrorPopupForCaptionCheck();
|
||||||
|
|
||||||
void showExternalMap(UploadItem uploadItem);
|
void showExternalMap(UploadItem uploadItem);
|
||||||
|
|
||||||
void showEditActivity(UploadItem uploadItem);
|
void showEditActivity(UploadItem uploadItem);
|
||||||
|
|
@ -50,7 +60,41 @@ public interface UploadMediaDetailsContract {
|
||||||
|
|
||||||
void setUploadMediaDetails(List<UploadMediaDetail> uploadMediaDetails, int uploadItemIndex);
|
void setUploadMediaDetails(List<UploadMediaDetail> uploadMediaDetails, int uploadItemIndex);
|
||||||
|
|
||||||
boolean verifyImageQuality(int uploadItemIndex, LatLng inAppPictureLocation);
|
/**
|
||||||
|
* Calculates the image quality
|
||||||
|
*
|
||||||
|
* @param uploadItemIndex Index of the UploadItem whose quality is to be checked
|
||||||
|
* @param inAppPictureLocation In app picture location (if any)
|
||||||
|
* @param activity Context reference
|
||||||
|
* @return true if no internal error occurs, else returns false
|
||||||
|
*/
|
||||||
|
boolean getImageQuality(int uploadItemIndex, LatLng inAppPictureLocation, Activity activity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the image has a location or not. Displays a dialog alerting user that no
|
||||||
|
* location has been to added to the image and asking them to add one
|
||||||
|
*
|
||||||
|
* @param uploadItemIndex Index of the uploadItem which has no location
|
||||||
|
* @param inAppPictureLocation In app picture location (if any)
|
||||||
|
*/
|
||||||
|
void displayLocDialog(int uploadItemIndex, LatLng inAppPictureLocation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to check image quality from stored qualities and display dialogs
|
||||||
|
*
|
||||||
|
* @param uploadItem UploadItem whose quality is to be checked
|
||||||
|
* @param index Index of the UploadItem whose quality is to be checked
|
||||||
|
*/
|
||||||
|
void checkImageQuality(UploadItem uploadItem, int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the image qualities stored in JSON, whenever an image is deleted
|
||||||
|
*
|
||||||
|
* @param size Size of uploadableFiles
|
||||||
|
* @param index Index of the UploadItem which was deleted
|
||||||
|
*/
|
||||||
|
void updateImageQualitiesJSON(int size, int index);
|
||||||
|
|
||||||
|
|
||||||
void copyTitleAndDescriptionToSubsequentMedia(int indexInViewFlipper);
|
void copyTitleAndDescriptionToSubsequentMedia(int indexInViewFlipper);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,31 @@ package fr.free.nrw.commons.upload.mediaDetails;
|
||||||
|
|
||||||
import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
|
import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
|
||||||
import static fr.free.nrw.commons.di.CommonsApplicationModule.MAIN_THREAD;
|
import static fr.free.nrw.commons.di.CommonsApplicationModule.MAIN_THREAD;
|
||||||
|
import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.activity;
|
||||||
import static fr.free.nrw.commons.utils.ImageUtils.EMPTY_CAPTION;
|
import static fr.free.nrw.commons.utils.ImageUtils.EMPTY_CAPTION;
|
||||||
import static fr.free.nrw.commons.utils.ImageUtils.FILE_NAME_EXISTS;
|
import static fr.free.nrw.commons.utils.ImageUtils.FILE_NAME_EXISTS;
|
||||||
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_KEEP;
|
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_KEEP;
|
||||||
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK;
|
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK;
|
||||||
|
import static fr.free.nrw.commons.utils.ImageUtils.getErrorMessageForResult;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.filepicker.UploadableFile;
|
import fr.free.nrw.commons.filepicker.UploadableFile;
|
||||||
|
import fr.free.nrw.commons.kvstore.BasicKvStore;
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
import fr.free.nrw.commons.nearby.Place;
|
||||||
import fr.free.nrw.commons.repository.UploadRepository;
|
import fr.free.nrw.commons.repository.UploadRepository;
|
||||||
import fr.free.nrw.commons.upload.ImageCoordinates;
|
import fr.free.nrw.commons.upload.ImageCoordinates;
|
||||||
import fr.free.nrw.commons.upload.SimilarImageInterface;
|
import fr.free.nrw.commons.upload.SimilarImageInterface;
|
||||||
|
import fr.free.nrw.commons.upload.UploadActivity;
|
||||||
import fr.free.nrw.commons.upload.UploadItem;
|
import fr.free.nrw.commons.upload.UploadItem;
|
||||||
import fr.free.nrw.commons.upload.UploadMediaDetail;
|
import fr.free.nrw.commons.upload.UploadMediaDetail;
|
||||||
|
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.UploadMediaDetailFragmentCallback;
|
||||||
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailsContract.UserActionListener;
|
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailsContract.UserActionListener;
|
||||||
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailsContract.View;
|
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailsContract.View;
|
||||||
|
import fr.free.nrw.commons.utils.DialogUtil;
|
||||||
import io.github.coordinates2country.Coordinates2Country;
|
import io.github.coordinates2country.Coordinates2Country;
|
||||||
import io.reactivex.Maybe;
|
import io.reactivex.Maybe;
|
||||||
import io.reactivex.Scheduler;
|
import io.reactivex.Scheduler;
|
||||||
|
|
@ -35,7 +42,9 @@ import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.json.JSONObject;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class UploadMediaPresenter implements UserActionListener, SimilarImageInterface {
|
public class UploadMediaPresenter implements UserActionListener, SimilarImageInterface {
|
||||||
|
|
@ -55,9 +64,18 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
|
||||||
private Scheduler ioScheduler;
|
private Scheduler ioScheduler;
|
||||||
private Scheduler mainThreadScheduler;
|
private Scheduler mainThreadScheduler;
|
||||||
|
|
||||||
|
public static UploadMediaDetailFragmentCallback presenterCallback ;
|
||||||
|
|
||||||
private final List<String> WLM_SUPPORTED_COUNTRIES= Arrays.asList("am","at","az","br","hr","sv","fi","fr","de","gh","in","ie","il","mk","my","mt","pk","pe","pl","ru","rw","si","es","se","tw","ug","ua","us");
|
private final List<String> WLM_SUPPORTED_COUNTRIES= Arrays.asList("am","at","az","br","hr","sv","fi","fr","de","gh","in","ie","il","mk","my","mt","pk","pe","pl","ru","rw","si","es","se","tw","ug","ua","us");
|
||||||
private Map<String, String> countryNamesAndCodes = null;
|
private Map<String, String> countryNamesAndCodes = null;
|
||||||
|
|
||||||
|
private final String keyForCurrentUploadImageQualities = "UploadedImagesQualities";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable used to determine if the battery-optimisation dialog is being shown or not
|
||||||
|
*/
|
||||||
|
public static boolean isBatteryDialogShowing;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public UploadMediaPresenter(UploadRepository uploadRepository,
|
public UploadMediaPresenter(UploadRepository uploadRepository,
|
||||||
@Named("default_preferences") JsonKvStore defaultKVStore,
|
@Named("default_preferences") JsonKvStore defaultKVStore,
|
||||||
|
|
@ -123,10 +141,10 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
|
||||||
{
|
{
|
||||||
view.onImageProcessed(uploadItem, place);
|
view.onImageProcessed(uploadItem, place);
|
||||||
view.updateMediaDetails(uploadItem.getUploadMediaDetails());
|
view.updateMediaDetails(uploadItem.getUploadMediaDetails());
|
||||||
|
view.showProgress(false);
|
||||||
final ImageCoordinates gpsCoords = uploadItem.getGpsCoords();
|
final ImageCoordinates gpsCoords = uploadItem.getGpsCoords();
|
||||||
final boolean hasImageCoordinates =
|
final boolean hasImageCoordinates =
|
||||||
gpsCoords != null && gpsCoords.getImageCoordsExists();
|
gpsCoords != null && gpsCoords.getImageCoordsExists();
|
||||||
view.showProgress(false);
|
|
||||||
if (hasImageCoordinates && place == null) {
|
if (hasImageCoordinates && place == null) {
|
||||||
checkNearbyPlaces(uploadItem);
|
checkNearbyPlaces(uploadItem);
|
||||||
}
|
}
|
||||||
|
|
@ -184,59 +202,45 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* asks the repository to verify image quality
|
* Checks if the image has a location or not. Displays a dialog alerting user that no
|
||||||
|
* location has been to added to the image and asking them to add one
|
||||||
*
|
*
|
||||||
* @param uploadItemIndex
|
* @param uploadItemIndex Index of the uploadItem which has no location
|
||||||
|
* @param inAppPictureLocation In app picture location (if any)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean verifyImageQuality(int uploadItemIndex, LatLng inAppPictureLocation) {
|
public void displayLocDialog(int uploadItemIndex, LatLng inAppPictureLocation) {
|
||||||
final List<UploadItem> uploadItems = repository.getUploads();
|
final List<UploadItem> uploadItems = repository.getUploads();
|
||||||
if (uploadItems.size()==0) {
|
|
||||||
view.showProgress(false);
|
|
||||||
// No internationalization required for this error message because it's an internal error.
|
|
||||||
view.showMessage("Internal error: Zero upload items received by the Upload Media Detail Fragment. Sorry, please upload again.",R.color.color_error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
UploadItem uploadItem = uploadItems.get(uploadItemIndex);
|
UploadItem uploadItem = uploadItems.get(uploadItemIndex);
|
||||||
|
|
||||||
if (uploadItem.getGpsCoords().getDecimalCoords() == null && inAppPictureLocation == null) {
|
if (uploadItem.getGpsCoords().getDecimalCoords() == null && inAppPictureLocation == null) {
|
||||||
final Runnable onSkipClicked = () -> {
|
final Runnable onSkipClicked = () -> {
|
||||||
view.showProgress(true);
|
verifyCaptionQuality(uploadItem);
|
||||||
compositeDisposable.add(
|
|
||||||
repository
|
|
||||||
.getImageQuality(uploadItem, inAppPictureLocation)
|
|
||||||
.observeOn(mainThreadScheduler)
|
|
||||||
.subscribe(imageResult -> {
|
|
||||||
view.showProgress(false);
|
|
||||||
handleImageResult(imageResult, uploadItem);
|
|
||||||
},
|
|
||||||
throwable -> {
|
|
||||||
view.showProgress(false);
|
|
||||||
if (throwable instanceof UnknownHostException) {
|
|
||||||
view.showConnectionErrorPopup();
|
|
||||||
} else {
|
|
||||||
view.showMessage("" + throwable.getLocalizedMessage(),
|
|
||||||
R.color.color_error);
|
|
||||||
}
|
|
||||||
Timber.e(throwable, "Error occurred while handling image");
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
view.displayAddLocationDialog(onSkipClicked);
|
view.displayAddLocationDialog(onSkipClicked);
|
||||||
} else {
|
} else {
|
||||||
|
verifyCaptionQuality(uploadItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the image's caption and calls function to handle the result
|
||||||
|
*
|
||||||
|
* @param uploadItem UploadItem whose caption is checked
|
||||||
|
*/
|
||||||
|
private void verifyCaptionQuality(UploadItem uploadItem) {
|
||||||
view.showProgress(true);
|
view.showProgress(true);
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
repository
|
repository
|
||||||
.getImageQuality(uploadItem, inAppPictureLocation)
|
.getCaptionQuality(uploadItem)
|
||||||
.observeOn(mainThreadScheduler)
|
.observeOn(mainThreadScheduler)
|
||||||
.subscribe(imageResult -> {
|
.subscribe(capResult -> {
|
||||||
view.showProgress(false);
|
view.showProgress(false);
|
||||||
handleImageResult(imageResult, uploadItem);
|
handleCaptionResult(capResult, uploadItem);
|
||||||
},
|
},
|
||||||
throwable -> {
|
throwable -> {
|
||||||
view.showProgress(false);
|
view.showProgress(false);
|
||||||
if (throwable instanceof UnknownHostException) {
|
if (throwable instanceof UnknownHostException) {
|
||||||
view.showConnectionErrorPopup();
|
view.showConnectionErrorPopupForCaptionCheck();
|
||||||
} else {
|
} else {
|
||||||
view.showMessage("" + throwable.getLocalizedMessage(),
|
view.showMessage("" + throwable.getLocalizedMessage(),
|
||||||
R.color.color_error);
|
R.color.color_error);
|
||||||
|
|
@ -245,7 +249,31 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
/**
|
||||||
|
* Handles image's caption results and shows dialog if necessary
|
||||||
|
*
|
||||||
|
* @param errorCode Error code of the UploadItem
|
||||||
|
* @param uploadItem UploadItem whose caption is checked
|
||||||
|
*/
|
||||||
|
public void handleCaptionResult(Integer errorCode, UploadItem uploadItem) {
|
||||||
|
// If errorCode is empty caption show message
|
||||||
|
if (errorCode == EMPTY_CAPTION) {
|
||||||
|
Timber.d("Captions are empty. Showing toast");
|
||||||
|
view.showMessage(R.string.add_caption_toast, R.color.color_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If image with same file name exists check the bit in errorCode is set or not
|
||||||
|
if ((errorCode & FILE_NAME_EXISTS) != 0) {
|
||||||
|
Timber.d("Trying to show duplicate picture popup");
|
||||||
|
view.showDuplicatePicturePopup(uploadItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If caption is not duplicate or user still wants to upload it
|
||||||
|
if (errorCode == IMAGE_OK) {
|
||||||
|
Timber.d("Image captions are okay or user still wants to upload it");
|
||||||
|
view.onImageValidationSuccess();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -310,49 +338,192 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handles image quality verifications
|
* Calculates the image quality
|
||||||
*
|
*
|
||||||
* @param imageResult
|
* @param uploadItemIndex Index of the UploadItem whose quality is to be checked
|
||||||
* @param uploadItem
|
* @param inAppPictureLocation In app picture location (if any)
|
||||||
|
* @param activity Context reference
|
||||||
|
* @return true if no internal error occurs, else returns false
|
||||||
*/
|
*/
|
||||||
public void handleImageResult(Integer imageResult,
|
@Override
|
||||||
UploadItem uploadItem) {
|
public boolean getImageQuality(int uploadItemIndex, LatLng inAppPictureLocation,
|
||||||
if (imageResult == IMAGE_KEEP || imageResult == IMAGE_OK) {
|
Activity activity) {
|
||||||
view.onImageValidationSuccess();
|
final List<UploadItem> uploadItems = repository.getUploads();
|
||||||
uploadItem.setHasInvalidLocation(false);
|
view.showProgress(true);
|
||||||
|
if (uploadItems.size() == 0) {
|
||||||
|
view.showProgress(false);
|
||||||
|
// No internationalization required for this error message because it's an internal error.
|
||||||
|
view.showMessage(
|
||||||
|
"Internal error: Zero upload items received by the Upload Media Detail Fragment. Sorry, please upload again.",
|
||||||
|
R.color.color_error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
UploadItem uploadItem = uploadItems.get(uploadItemIndex);
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository
|
||||||
|
.getImageQuality(uploadItem, inAppPictureLocation)
|
||||||
|
.observeOn(mainThreadScheduler)
|
||||||
|
.subscribe(imageResult -> {
|
||||||
|
storeImageQuality(imageResult, uploadItemIndex, activity, uploadItem);
|
||||||
|
},
|
||||||
|
throwable -> {
|
||||||
|
if (throwable instanceof UnknownHostException) {
|
||||||
|
view.showProgress(false);
|
||||||
|
view.showConnectionErrorPopup();
|
||||||
} else {
|
} else {
|
||||||
handleBadImage(imageResult, uploadItem);
|
view.showMessage("" + throwable.getLocalizedMessage(),
|
||||||
|
R.color.color_error);
|
||||||
|
}
|
||||||
|
Timber.e(throwable, "Error occurred while handling image");
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the image quality in JSON format in SharedPrefs
|
||||||
|
*
|
||||||
|
* @param imageResult Image quality
|
||||||
|
* @param uploadItemIndex Index of the UploadItem whose quality is calculated
|
||||||
|
* @param activity Context reference
|
||||||
|
* @param uploadItem UploadItem whose quality is to be checked
|
||||||
|
*/
|
||||||
|
private void storeImageQuality(Integer imageResult, int uploadItemIndex, Activity activity,
|
||||||
|
UploadItem uploadItem) {
|
||||||
|
BasicKvStore store = new BasicKvStore(activity,
|
||||||
|
UploadActivity.storeNameForCurrentUploadImagesSize);
|
||||||
|
String value = store.getString(keyForCurrentUploadImageQualities, null);
|
||||||
|
JSONObject jsonObject;
|
||||||
|
try {
|
||||||
|
if (value != null) {
|
||||||
|
jsonObject = new JSONObject(value);
|
||||||
|
} else {
|
||||||
|
jsonObject = new JSONObject();
|
||||||
|
}
|
||||||
|
jsonObject.put("UploadItem" + uploadItemIndex, imageResult);
|
||||||
|
store.putString(keyForCurrentUploadImageQualities, jsonObject.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uploadItemIndex == 0) {
|
||||||
|
if (!isBatteryDialogShowing) {
|
||||||
|
// if battery-optimisation dialog is not being shown, call checkImageQuality
|
||||||
|
checkImageQuality(uploadItem, uploadItemIndex);
|
||||||
|
} else {
|
||||||
|
view.showProgress(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle images, say empty caption, duplicate file name, bad picture(in all other cases)
|
* Used to check image quality from stored qualities and display dialogs
|
||||||
*
|
*
|
||||||
* @param errorCode
|
* @param uploadItem UploadItem whose quality is to be checked
|
||||||
* @param uploadItem
|
* @param index Index of the UploadItem whose quality is to be checked
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void checkImageQuality(UploadItem uploadItem, int index) {
|
||||||
|
if ((uploadItem.getImageQuality() != IMAGE_OK) && (uploadItem.getImageQuality()
|
||||||
|
!= IMAGE_KEEP)) {
|
||||||
|
BasicKvStore store = new BasicKvStore(activity,
|
||||||
|
UploadActivity.storeNameForCurrentUploadImagesSize);
|
||||||
|
String value = store.getString(keyForCurrentUploadImageQualities, null);
|
||||||
|
JSONObject jsonObject;
|
||||||
|
try {
|
||||||
|
if (value != null) {
|
||||||
|
jsonObject = new JSONObject(value);
|
||||||
|
} else {
|
||||||
|
jsonObject = new JSONObject();
|
||||||
|
}
|
||||||
|
Integer imageQuality = (int) jsonObject.get("UploadItem" + index);
|
||||||
|
view.showProgress(false);
|
||||||
|
if (imageQuality == IMAGE_OK) {
|
||||||
|
uploadItem.setHasInvalidLocation(false);
|
||||||
|
uploadItem.setImageQuality(imageQuality);
|
||||||
|
} else {
|
||||||
|
handleBadImage(imageQuality, uploadItem, index);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the image qualities stored in JSON, whenever an image is deleted
|
||||||
|
*
|
||||||
|
* @param size Size of uploadableFiles
|
||||||
|
* @param index Index of the UploadItem which was deleted
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updateImageQualitiesJSON(int size, int index) {
|
||||||
|
BasicKvStore store = new BasicKvStore(activity,
|
||||||
|
UploadActivity.storeNameForCurrentUploadImagesSize);
|
||||||
|
String value = store.getString(keyForCurrentUploadImageQualities, null);
|
||||||
|
JSONObject jsonObject;
|
||||||
|
try {
|
||||||
|
if (value != null) {
|
||||||
|
jsonObject = new JSONObject(value);
|
||||||
|
} else {
|
||||||
|
jsonObject = new JSONObject();
|
||||||
|
}
|
||||||
|
for (int i = index; i < (size - 1); i++) {
|
||||||
|
jsonObject.put("UploadItem" + i, jsonObject.get("UploadItem" + (i + 1)));
|
||||||
|
}
|
||||||
|
jsonObject.remove("UploadItem" + (size - 1));
|
||||||
|
store.putString(keyForCurrentUploadImageQualities, jsonObject.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles bad pictures, like too dark, already on wikimedia, downloaded from internet
|
||||||
|
*
|
||||||
|
* @param errorCode Error code of the bad image quality
|
||||||
|
* @param uploadItem UploadItem whose quality is bad
|
||||||
|
* @param index Index of item whose quality is bad
|
||||||
*/
|
*/
|
||||||
public void handleBadImage(Integer errorCode,
|
public void handleBadImage(Integer errorCode,
|
||||||
UploadItem uploadItem) {
|
UploadItem uploadItem, int index) {
|
||||||
Timber.d("Handle bad picture with error code %d", errorCode);
|
Timber.d("Handle bad picture with error code %d", errorCode);
|
||||||
if (errorCode
|
if (errorCode >= 8) { // If location of image and nearby does not match
|
||||||
>= 8) { // If location of image and nearby does not match
|
|
||||||
uploadItem.setHasInvalidLocation(true);
|
uploadItem.setHasInvalidLocation(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If errorCode is empty caption show message
|
// If image has some other problems, show popup accordingly
|
||||||
if (errorCode == EMPTY_CAPTION) {
|
if (errorCode != EMPTY_CAPTION && errorCode != FILE_NAME_EXISTS) {
|
||||||
Timber.d("Captions are empty. Showing toast");
|
showBadImagePopup(errorCode, index, activity, uploadItem);
|
||||||
view.showMessage(R.string.add_caption_toast, R.color.color_error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If image has some problems, show popup accordingly
|
|
||||||
if (errorCode != EMPTY_CAPTION && errorCode != FILE_NAME_EXISTS) {
|
|
||||||
view.showBadImagePopup(errorCode, uploadItem);
|
|
||||||
} else if ((errorCode & FILE_NAME_EXISTS) != 0) {
|
|
||||||
// When image has duplicate caption problem
|
|
||||||
Timber.d("Trying to show duplicate picture popup");
|
|
||||||
view.showDuplicatePicturePopup(uploadItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a dialog describing the potential problems in the current image
|
||||||
|
*
|
||||||
|
* @param errorCode Has the potential problems in the current image
|
||||||
|
* @param index Index of the UploadItem which has problems
|
||||||
|
* @param activity Context reference
|
||||||
|
* @param uploadItem UploadItem which has problems
|
||||||
|
*/
|
||||||
|
public void showBadImagePopup(Integer errorCode,
|
||||||
|
int index, Activity activity, UploadItem uploadItem) {
|
||||||
|
String errorMessageForResult = getErrorMessageForResult(activity, errorCode);
|
||||||
|
if (!StringUtils.isBlank(errorMessageForResult)) {
|
||||||
|
DialogUtil.showAlertDialog(activity,
|
||||||
|
activity.getString(R.string.upload_problem_image),
|
||||||
|
errorMessageForResult,
|
||||||
|
activity.getString(R.string.upload),
|
||||||
|
activity.getString(R.string.cancel),
|
||||||
|
() -> {
|
||||||
|
view.showProgress(false);
|
||||||
|
uploadItem.setImageQuality(IMAGE_OK);
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
presenterCallback.deletePictureAtIndex(index);
|
||||||
|
}
|
||||||
|
).setCancelable(false);
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
//If the error message is null, we will probably not show anything
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ class ImageProcessingServiceTest {
|
||||||
fun validateImageForFileNameExistsWithCheckTitleOn() {
|
fun validateImageForFileNameExistsWithCheckTitleOn() {
|
||||||
`when`(mediaClient?.checkPageExistsUsingTitle(ArgumentMatchers.anyString()))
|
`when`(mediaClient?.checkPageExistsUsingTitle(ArgumentMatchers.anyString()))
|
||||||
.thenReturn(Single.just(true))
|
.thenReturn(Single.just(true))
|
||||||
val validateImage = imageProcessingService!!.validateImage(uploadItem, location)
|
val validateImage = imageProcessingService!!.validateCaption(uploadItem)
|
||||||
assertEquals(ImageUtils.FILE_NAME_EXISTS, validateImage.blockingGet())
|
assertEquals(ImageUtils.FILE_NAME_EXISTS, validateImage.blockingGet())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,9 @@ class UploadMediaPresenterTest {
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var jsonKvStore: JsonKvStore
|
private lateinit var jsonKvStore: JsonKvStore
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
lateinit var mockActivity: UploadActivity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initial setup unit test environment
|
* initial setup unit test environment
|
||||||
*/
|
*/
|
||||||
|
|
@ -79,8 +82,9 @@ class UploadMediaPresenterTest {
|
||||||
testObservableUploadItem = Observable.just(uploadItem)
|
testObservableUploadItem = Observable.just(uploadItem)
|
||||||
testSingleImageResult = Single.just(1)
|
testSingleImageResult = Single.just(1)
|
||||||
testScheduler = TestScheduler()
|
testScheduler = TestScheduler()
|
||||||
uploadMediaPresenter = UploadMediaPresenter(repository,
|
uploadMediaPresenter = UploadMediaPresenter(
|
||||||
jsonKvStore,testScheduler, testScheduler)
|
repository, jsonKvStore, testScheduler, testScheduler
|
||||||
|
)
|
||||||
uploadMediaPresenter.onAttachView(view)
|
uploadMediaPresenter.onAttachView(view)
|
||||||
mockedCountry = mockStatic(Coordinates2Country::class.java)
|
mockedCountry = mockStatic(Coordinates2Country::class.java)
|
||||||
}
|
}
|
||||||
|
|
@ -111,14 +115,13 @@ class UploadMediaPresenterTest {
|
||||||
ArgumentMatchers.any(UploadItem::class.java),
|
ArgumentMatchers.any(UploadItem::class.java),
|
||||||
ArgumentMatchers.any(Place::class.java)
|
ArgumentMatchers.any(Place::class.java)
|
||||||
)
|
)
|
||||||
verify(view).showProgress(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* unit test for method UploadMediaPresenter.verifyImageQuality (For else case)
|
* unit test for method UploadMediaPresenter.getImageQuality (For else case)
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun verifyImageQualityTest() {
|
fun getImageQualityTest() {
|
||||||
whenever(repository.uploads).thenReturn(listOf(uploadItem))
|
whenever(repository.uploads).thenReturn(listOf(uploadItem))
|
||||||
whenever(repository.getImageQuality(uploadItem, location))
|
whenever(repository.getImageQuality(uploadItem, location))
|
||||||
.thenReturn(testSingleImageResult)
|
.thenReturn(testSingleImageResult)
|
||||||
|
|
@ -127,17 +130,16 @@ class UploadMediaPresenterTest {
|
||||||
.thenReturn(imageCoordinates)
|
.thenReturn(imageCoordinates)
|
||||||
whenever(uploadItem.gpsCoords.decimalCoords)
|
whenever(uploadItem.gpsCoords.decimalCoords)
|
||||||
.thenReturn("imageCoordinates")
|
.thenReturn("imageCoordinates")
|
||||||
uploadMediaPresenter.verifyImageQuality(0, location)
|
uploadMediaPresenter.getImageQuality(0, location, mockActivity)
|
||||||
verify(view).showProgress(true)
|
verify(view).showProgress(true)
|
||||||
testScheduler.triggerActions()
|
testScheduler.triggerActions()
|
||||||
verify(view).showProgress(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* unit test for method UploadMediaPresenter.verifyImageQuality (For if case)
|
* unit test for method UploadMediaPresenter.getImageQuality (For if case)
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun `verify ImageQuality Test while coordinates equals to null`() {
|
fun `get ImageQuality Test while coordinates equals to null`() {
|
||||||
whenever(repository.uploads).thenReturn(listOf(uploadItem))
|
whenever(repository.uploads).thenReturn(listOf(uploadItem))
|
||||||
whenever(repository.getImageQuality(uploadItem, location))
|
whenever(repository.getImageQuality(uploadItem, location))
|
||||||
.thenReturn(testSingleImageResult)
|
.thenReturn(testSingleImageResult)
|
||||||
|
|
@ -146,30 +148,35 @@ class UploadMediaPresenterTest {
|
||||||
.thenReturn(imageCoordinates)
|
.thenReturn(imageCoordinates)
|
||||||
whenever(uploadItem.gpsCoords.decimalCoords)
|
whenever(uploadItem.gpsCoords.decimalCoords)
|
||||||
.thenReturn(null)
|
.thenReturn(null)
|
||||||
uploadMediaPresenter.verifyImageQuality(0, location)
|
uploadMediaPresenter.getImageQuality(0, location, mockActivity)
|
||||||
testScheduler.triggerActions()
|
testScheduler.triggerActions()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* unit test for method UploadMediaPresenter.handleImageResult
|
* Test for empty file name when the user presses the NEXT button
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun handleImageResult() {
|
fun emptyFileNameTest() {
|
||||||
//Positive case test
|
uploadMediaPresenter.handleCaptionResult(EMPTY_CAPTION, uploadItem);
|
||||||
uploadMediaPresenter.handleImageResult(IMAGE_KEEP, uploadItem)
|
|
||||||
verify(view).onImageValidationSuccess()
|
|
||||||
|
|
||||||
//Duplicate file name
|
|
||||||
uploadMediaPresenter.handleImageResult(FILE_NAME_EXISTS, uploadItem)
|
|
||||||
verify(view).showDuplicatePicturePopup(uploadItem)
|
|
||||||
|
|
||||||
//Empty Caption test
|
|
||||||
uploadMediaPresenter.handleImageResult(EMPTY_CAPTION, uploadItem)
|
|
||||||
verify(view).showMessage(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())
|
verify(view).showMessage(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())
|
||||||
|
}
|
||||||
|
|
||||||
// Bad Picture Test
|
/**
|
||||||
uploadMediaPresenter.handleImageResult(-7, uploadItem)
|
* Test for duplicate file name when the user presses the NEXT button
|
||||||
verify(view)?.showBadImagePopup(ArgumentMatchers.anyInt(), ArgumentMatchers.eq(uploadItem))
|
*/
|
||||||
|
@Test
|
||||||
|
fun duplicateFileNameTest() {
|
||||||
|
uploadMediaPresenter.handleCaptionResult(FILE_NAME_EXISTS, uploadItem)
|
||||||
|
verify(view).showDuplicatePicturePopup(uploadItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for correct file name when the user presses the NEXT button
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun correctFileNameTest() {
|
||||||
|
uploadMediaPresenter.handleCaptionResult(IMAGE_OK, uploadItem)
|
||||||
|
verify(view).onImageValidationSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -218,34 +225,6 @@ class UploadMediaPresenterTest {
|
||||||
verify(view).updateMediaDetails(ArgumentMatchers.any())
|
verify(view).updateMediaDetails(ArgumentMatchers.any())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test bad image invalid location
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun handleBadImageBaseTestInvalidLocation() {
|
|
||||||
uploadMediaPresenter.handleBadImage(8, uploadItem)
|
|
||||||
verify(view).showBadImagePopup(8, uploadItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test bad image empty title
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun handleBadImageBaseTestEmptyTitle() {
|
|
||||||
uploadMediaPresenter.handleBadImage(-3, uploadItem)
|
|
||||||
verify(view).showMessage(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Teste show file already exists
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun handleBadImageBaseTestFileNameExists() {
|
|
||||||
uploadMediaPresenter.handleBadImage(64, uploadItem)
|
|
||||||
verify(view).showDuplicatePicturePopup(uploadItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test show SimilarImageFragment
|
* Test show SimilarImageFragment
|
||||||
*/
|
*/
|
||||||
|
|
@ -259,7 +238,8 @@ class UploadMediaPresenterTest {
|
||||||
@Test
|
@Test
|
||||||
fun setCorrectCountryCodeForReceivedImage() {
|
fun setCorrectCountryCodeForReceivedImage() {
|
||||||
|
|
||||||
val germanyAsPlace = Place(null,null, null, null, LatLng(50.1, 10.2, 1.0f), null, null, null, true)
|
val germanyAsPlace =
|
||||||
|
Place(null, null, null, null, LatLng(50.1, 10.2, 1.0f), null, null, null, true)
|
||||||
germanyAsPlace.isMonument = true
|
germanyAsPlace.isMonument = true
|
||||||
|
|
||||||
whenever(
|
whenever(
|
||||||
|
|
@ -269,7 +249,8 @@ class UploadMediaPresenterTest {
|
||||||
)
|
)
|
||||||
).thenReturn("Germany")
|
).thenReturn("Germany")
|
||||||
|
|
||||||
val item: Observable<UploadItem> = Observable.just(UploadItem(Uri.EMPTY, null, null, germanyAsPlace, 0, null, null, null))
|
val item: Observable<UploadItem> =
|
||||||
|
Observable.just(UploadItem(Uri.EMPTY, null, null, germanyAsPlace, 0, null, null, null))
|
||||||
|
|
||||||
whenever(
|
whenever(
|
||||||
repository.preProcessImage(
|
repository.preProcessImage(
|
||||||
|
|
@ -291,7 +272,5 @@ class UploadMediaPresenterTest {
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals("Exptected contry code", "de", captor.value.countryCode);
|
assertEquals("Exptected contry code", "de", captor.value.countryCode);
|
||||||
|
|
||||||
verify(view).showProgress(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,15 @@ class UploadRepositoryUnitTest {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testGetCaptionQuality() {
|
||||||
|
assertEquals(
|
||||||
|
repository.getCaptionQuality(uploadItem),
|
||||||
|
uploadModel.getCaptionQuality(uploadItem)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testDeletePicture() {
|
fun testDeletePicture() {
|
||||||
assertEquals(repository.deletePicture(""), uploadModel.deletePicture(""))
|
assertEquals(repository.deletePicture(""), uploadModel.deletePicture(""))
|
||||||
|
|
|
||||||
|
|
@ -321,18 +321,12 @@ class UploadMediaDetailFragmentUnitTest {
|
||||||
fragment.showDuplicatePicturePopup(uploadItem)
|
fragment.showDuplicatePicturePopup(uploadItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun testShowBadImagePopup() {
|
|
||||||
Shadows.shadowOf(Looper.getMainLooper()).idle()
|
|
||||||
fragment.showBadImagePopup(8, uploadItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun testShowConnectionErrorPopup() {
|
fun testShowConnectionErrorPopupForCaptionCheck() {
|
||||||
Shadows.shadowOf(Looper.getMainLooper()).idle()
|
Shadows.shadowOf(Looper.getMainLooper()).idle()
|
||||||
fragment.showConnectionErrorPopup()
|
fragment.showConnectionErrorPopupForCaptionCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -364,7 +358,7 @@ class UploadMediaDetailFragmentUnitTest {
|
||||||
`when`(latLng.longitude).thenReturn(0.0)
|
`when`(latLng.longitude).thenReturn(0.0)
|
||||||
`when`(uploadItem.gpsCoords).thenReturn(imageCoordinates)
|
`when`(uploadItem.gpsCoords).thenReturn(imageCoordinates)
|
||||||
fragment.onActivityResult(1211, Activity.RESULT_OK, intent)
|
fragment.onActivityResult(1211, Activity.RESULT_OK, intent)
|
||||||
Mockito.verify(presenter, Mockito.times(0)).verifyImageQuality(0, location)
|
Mockito.verify(presenter, Mockito.times(0)).getImageQuality(0, location, activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -388,7 +382,7 @@ class UploadMediaDetailFragmentUnitTest {
|
||||||
`when`(latLng.longitude).thenReturn(0.0)
|
`when`(latLng.longitude).thenReturn(0.0)
|
||||||
`when`(uploadItem.gpsCoords).thenReturn(imageCoordinates)
|
`when`(uploadItem.gpsCoords).thenReturn(imageCoordinates)
|
||||||
fragment.onActivityResult(1211, Activity.RESULT_OK, intent)
|
fragment.onActivityResult(1211, Activity.RESULT_OK, intent)
|
||||||
Mockito.verify(presenter, Mockito.times(1)).verifyImageQuality(0, null)
|
Mockito.verify(presenter, Mockito.times(1)).displayLocDialog(0, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -398,17 +392,6 @@ class UploadMediaDetailFragmentUnitTest {
|
||||||
fragment.updateMediaDetails(null)
|
fragment.updateMediaDetails(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@Throws(Exception::class)
|
|
||||||
fun testDeleteThisPicture() {
|
|
||||||
Shadows.shadowOf(Looper.getMainLooper()).idle()
|
|
||||||
val method: Method = UploadMediaDetailFragment::class.java.getDeclaredMethod(
|
|
||||||
"deleteThisPicture"
|
|
||||||
)
|
|
||||||
method.isAccessible = true
|
|
||||||
method.invoke(fragment)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun testOnDestroyView() {
|
fun testOnDestroyView() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue