mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-31 14:53:59 +01:00 
			
		
		
		
	Added image duplicity check on restart of failed image
This commit is contained in:
		
							parent
							
								
									ae00a9d19f
								
							
						
					
					
						commit
						e96cc8b5ca
					
				
					 6 changed files with 135 additions and 47 deletions
				
			
		|  | @ -5,6 +5,7 @@ import static fr.free.nrw.commons.contributions.Contribution.STATE_FAILED; | |||
| import static fr.free.nrw.commons.contributions.Contribution.STATE_PAUSED; | ||||
| import static fr.free.nrw.commons.nearby.fragments.NearbyParentFragment.WLM_URL; | ||||
| import static fr.free.nrw.commons.profile.ProfileActivity.KEY_USERNAME; | ||||
| import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK; | ||||
| import static fr.free.nrw.commons.utils.LengthUtils.computeBearing; | ||||
| import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween; | ||||
| 
 | ||||
|  | @ -831,10 +832,18 @@ public class ContributionsFragment | |||
|      * @param contribution | ||||
|      */ | ||||
|     public void restartUpload(Contribution contribution) { | ||||
|         contribution.setState(Contribution.STATE_QUEUED); | ||||
|         contribution.setDateUploadStarted(Calendar.getInstance().getTime()); | ||||
|         contributionsPresenter.saveContribution(contribution); | ||||
|         Timber.d("Restarting for %s", contribution.toString()); | ||||
|         if (contribution.getState() == Contribution.STATE_FAILED) { | ||||
|             if (contribution.getErrorInfo() == null){ | ||||
|                 contribution.setChunkInfo(null); | ||||
|                 contribution.setTransferred(0); | ||||
|             } | ||||
|             contributionsPresenter.checkDuplicateImageAndRestartContribution(contribution); | ||||
|         } else { | ||||
|             contribution.setState(Contribution.STATE_QUEUED); | ||||
|             contributionsPresenter.saveContribution(contribution); | ||||
|             Timber.d("Restarting for %s", contribution.toString()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -856,10 +865,6 @@ public class ContributionsFragment | |||
|                     contribution.setRetries(retries + 1); | ||||
|                     Timber.d("Retried uploading %s %d times", contribution.getMedia().getFilename(), | ||||
|                         retries + 1); | ||||
|                     if (contribution.getErrorInfo() == null){ | ||||
|                         contribution.setChunkInfo(null); | ||||
|                         contribution.setTransferred(0); | ||||
|                     } | ||||
|                     restartUpload(contribution); | ||||
|                 } else { | ||||
|                     // TODO: Show the exact reason for failure | ||||
|  |  | |||
|  | @ -1,21 +1,26 @@ | |||
| package fr.free.nrw.commons.contributions; | ||||
| 
 | ||||
| import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK; | ||||
| 
 | ||||
| import androidx.work.ExistingWorkPolicy; | ||||
| import fr.free.nrw.commons.MediaDataExtractor; | ||||
| import fr.free.nrw.commons.contributions.ContributionsContract.UserActionListener; | ||||
| import fr.free.nrw.commons.di.CommonsApplicationModule; | ||||
| import fr.free.nrw.commons.repository.UploadRepository; | ||||
| import fr.free.nrw.commons.upload.worker.WorkRequestHelper; | ||||
| import io.reactivex.Scheduler; | ||||
| import io.reactivex.disposables.CompositeDisposable; | ||||
| import javax.inject.Inject; | ||||
| import javax.inject.Named; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| /** | ||||
|  * The presenter class for Contributions | ||||
|  */ | ||||
| public class ContributionsPresenter implements UserActionListener { | ||||
| 
 | ||||
|     private final ContributionsRepository repository; | ||||
|     private final ContributionsRepository contributionsRepository; | ||||
|     private final UploadRepository uploadRepository; | ||||
|     private final Scheduler ioThreadScheduler; | ||||
|     private CompositeDisposable compositeDisposable; | ||||
|     private ContributionsContract.View view; | ||||
|  | @ -25,8 +30,10 @@ public class ContributionsPresenter implements UserActionListener { | |||
| 
 | ||||
|     @Inject | ||||
|     ContributionsPresenter(ContributionsRepository repository, | ||||
|         UploadRepository uploadRepository, | ||||
|         @Named(CommonsApplicationModule.IO_THREAD) Scheduler ioThreadScheduler) { | ||||
|         this.repository = repository; | ||||
|         this.contributionsRepository = repository; | ||||
|         this.uploadRepository = uploadRepository; | ||||
|         this.ioThreadScheduler=ioThreadScheduler; | ||||
|     } | ||||
| 
 | ||||
|  | @ -44,7 +51,25 @@ public class ContributionsPresenter implements UserActionListener { | |||
| 
 | ||||
|     @Override | ||||
|     public Contribution getContributionsWithTitle(String title) { | ||||
|         return repository.getContributionWithFileName(title); | ||||
|         return contributionsRepository.getContributionWithFileName(title); | ||||
|     } | ||||
| 
 | ||||
|     public void checkDuplicateImageAndRestartContribution(Contribution contribution){ | ||||
|         compositeDisposable.add(uploadRepository | ||||
|             .checkDuplicateImage(contribution.getLocalUriPath().getPath()) | ||||
|             .subscribeOn(ioThreadScheduler) | ||||
|             .subscribe(imageCheckResult -> { | ||||
|                 if (imageCheckResult == IMAGE_OK) { | ||||
|                     contribution.setState(Contribution.STATE_QUEUED); | ||||
|                     saveContribution(contribution); | ||||
|                 }else { | ||||
|                     Timber.e("Contribution already exists"); | ||||
|                     compositeDisposable.add(contributionsRepository | ||||
|                         .deleteContributionFromDB(contribution) | ||||
|                         .subscribeOn(ioThreadScheduler) | ||||
|                         .subscribe()); | ||||
|                 } | ||||
|             })); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -54,7 +79,7 @@ public class ContributionsPresenter implements UserActionListener { | |||
|      * @param contribution | ||||
|      */ | ||||
|     public void saveContribution(Contribution contribution) { | ||||
|         compositeDisposable.add(repository | ||||
|         compositeDisposable.add(contributionsRepository | ||||
|             .save(contribution) | ||||
|             .subscribeOn(ioThreadScheduler) | ||||
|             .subscribe(() -> WorkRequestHelper.Companion.makeOneTimeWorkRequest( | ||||
|  |  | |||
|  | @ -203,6 +203,16 @@ public class UploadRepository { | |||
|         return uploadModel.getImageQuality(uploadItem, location); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * query the RemoteDataSource for image duplicity check | ||||
|      * | ||||
|      * @param filePath file to be checked | ||||
|      * @return IMAGE_DUPLICATE or IMAGE_OK | ||||
|      */ | ||||
|     public Single<Integer> checkDuplicateImage(String filePath) { | ||||
|         return uploadModel.checkDuplicateImage(filePath); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * query the RemoteDataSource for caption quality | ||||
|      * | ||||
|  |  | |||
|  | @ -140,7 +140,7 @@ public class ImageProcessingService { | |||
|      * @param filePath file to be checked | ||||
|      * @return IMAGE_DUPLICATE or IMAGE_OK | ||||
|      */ | ||||
|     private Single<Integer> checkDuplicateImage(String filePath) { | ||||
|     Single<Integer> checkDuplicateImage(String filePath) { | ||||
|         Timber.d("Checking for duplicate image %s", filePath); | ||||
|         return Single.fromCallable(() -> fileUtilsWrapper.getFileInputStream(filePath)) | ||||
|             .map(fileUtilsWrapper::getSHA1) | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| package fr.free.nrw.commons.upload; | ||||
| 
 | ||||
| 
 | ||||
| import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.lifecycle.LiveData; | ||||
|  | @ -14,6 +16,7 @@ import fr.free.nrw.commons.contributions.ContributionBoundaryCallback; | |||
| import fr.free.nrw.commons.contributions.ContributionsRemoteDataSource; | ||||
| import fr.free.nrw.commons.contributions.ContributionsRepository; | ||||
| import fr.free.nrw.commons.di.CommonsApplicationModule; | ||||
| import fr.free.nrw.commons.repository.UploadRepository; | ||||
| import fr.free.nrw.commons.upload.PendingUploadsContract.UserActionListener; | ||||
| import fr.free.nrw.commons.upload.PendingUploadsContract.View; | ||||
| import fr.free.nrw.commons.upload.worker.WorkRequestHelper; | ||||
|  | @ -33,7 +36,8 @@ import timber.log.Timber; | |||
| public class PendingUploadsPresenter implements UserActionListener { | ||||
| 
 | ||||
|     private final ContributionBoundaryCallback contributionBoundaryCallback; | ||||
|     private final ContributionsRepository repository; | ||||
|     private final ContributionsRepository contributionsRepository; | ||||
|     private final UploadRepository uploadRepository; | ||||
|     private final Scheduler ioThreadScheduler; | ||||
| 
 | ||||
|     private final CompositeDisposable compositeDisposable; | ||||
|  | @ -46,10 +50,12 @@ public class PendingUploadsPresenter implements UserActionListener { | |||
|     PendingUploadsPresenter( | ||||
|         final ContributionBoundaryCallback contributionBoundaryCallback, | ||||
|         final ContributionsRemoteDataSource contributionsRemoteDataSource, | ||||
|         final ContributionsRepository repository, | ||||
|         final ContributionsRepository contributionsRepository, | ||||
|         final UploadRepository uploadRepository, | ||||
|         @Named(CommonsApplicationModule.IO_THREAD) final Scheduler ioThreadScheduler) { | ||||
|         this.contributionBoundaryCallback = contributionBoundaryCallback; | ||||
|         this.repository = repository; | ||||
|         this.contributionsRepository = contributionsRepository; | ||||
|         this.uploadRepository = uploadRepository; | ||||
|         this.ioThreadScheduler = ioThreadScheduler; | ||||
|         this.contributionsRemoteDataSource = contributionsRemoteDataSource; | ||||
|         compositeDisposable = new CompositeDisposable(); | ||||
|  | @ -68,7 +74,7 @@ public class PendingUploadsPresenter implements UserActionListener { | |||
|                 .setPageSize(10).build(); | ||||
|         Factory<Integer, Contribution> factory; | ||||
| 
 | ||||
|         factory = repository.fetchContributionsWithStatesSortedByDateUploadStarted( | ||||
|         factory = contributionsRepository.fetchContributionsWithStatesSortedByDateUploadStarted( | ||||
|             Arrays.asList(Contribution.STATE_QUEUED, Contribution.STATE_IN_PROGRESS, | ||||
|                 Contribution.STATE_PAUSED)); | ||||
|         LivePagedListBuilder livePagedListBuilder = new LivePagedListBuilder(factory, | ||||
|  | @ -82,7 +88,7 @@ public class PendingUploadsPresenter implements UserActionListener { | |||
|                 .setPrefetchDistance(50) | ||||
|                 .setPageSize(10).build(); | ||||
|         Factory<Integer, Contribution> factory; | ||||
|         factory = repository.fetchContributionsWithStatesSortedByDateUploadStarted( | ||||
|         factory = contributionsRepository.fetchContributionsWithStatesSortedByDateUploadStarted( | ||||
|             Collections.singletonList(Contribution.STATE_FAILED)); | ||||
|         LivePagedListBuilder livePagedListBuilder = new LivePagedListBuilder(factory, | ||||
|             pagedListConfig); | ||||
|  | @ -103,7 +109,7 @@ public class PendingUploadsPresenter implements UserActionListener { | |||
| 
 | ||||
|     @Override | ||||
|     public void deleteUpload(final Contribution contribution, Context context) { | ||||
|         compositeDisposable.add(repository | ||||
|         compositeDisposable.add(contributionsRepository | ||||
|             .deleteContributionFromDB(contribution) | ||||
|             .subscribeOn(ioThreadScheduler) | ||||
|             .subscribe()); | ||||
|  | @ -111,14 +117,14 @@ public class PendingUploadsPresenter implements UserActionListener { | |||
| 
 | ||||
|     public void pauseUploads(List<Integer> states, int newState) { | ||||
|         CommonsApplication.isPaused = true ; | ||||
|         compositeDisposable.add(repository | ||||
|         compositeDisposable.add(contributionsRepository | ||||
|             .updateContributionWithStates(states, newState) | ||||
|             .subscribeOn(ioThreadScheduler) | ||||
|             .subscribe()); | ||||
|     } | ||||
| 
 | ||||
|     public void deleteUploads(List<Integer> states) { | ||||
|         compositeDisposable.add(repository | ||||
|         compositeDisposable.add(contributionsRepository | ||||
|             .deleteContributionsFromDBWithStates(states) | ||||
|             .subscribeOn(ioThreadScheduler) | ||||
|             .subscribe()); | ||||
|  | @ -132,27 +138,46 @@ public class PendingUploadsPresenter implements UserActionListener { | |||
|         Contribution it = contributionList.get(index); | ||||
|         if (it.getState() == Contribution.STATE_FAILED) { | ||||
|             it.setDateUploadStarted(Calendar.getInstance().getTime()); | ||||
|             if (it.getErrorInfo() == null){ | ||||
|             if (it.getErrorInfo() == null) { | ||||
|                 it.setChunkInfo(null); | ||||
|                 it.setTransferred(0); | ||||
|             } | ||||
|         } | ||||
|         it.setState(Contribution.STATE_QUEUED); | ||||
|         compositeDisposable.add(repository | ||||
|             .save(it) | ||||
|             .subscribeOn(ioThreadScheduler) | ||||
|             .doOnComplete(() -> { | ||||
|                     restartUploads(contributionList, index + 1, context); | ||||
|                 } | ||||
|             ) | ||||
|             .subscribe(() -> | ||||
|                     WorkRequestHelper.Companion.makeOneTimeWorkRequest( | ||||
|                         context, ExistingWorkPolicy.KEEP), | ||||
|                 throwable -> { | ||||
|             compositeDisposable.add(uploadRepository | ||||
|                 .checkDuplicateImage(it.getLocalUriPath().getPath()) | ||||
|                 .subscribeOn(ioThreadScheduler) | ||||
|                 .subscribe(imageCheckResult -> { | ||||
|                     if (imageCheckResult == IMAGE_OK) { | ||||
|                         it.setState(Contribution.STATE_QUEUED); | ||||
|                         compositeDisposable.add(contributionsRepository | ||||
|                             .save(it) | ||||
|                             .subscribeOn(ioThreadScheduler) | ||||
|                             .doOnComplete(() -> { | ||||
|                                 restartUploads(contributionList, index + 1, context); | ||||
|                             }) | ||||
|                             .subscribe()); | ||||
|                     } else { | ||||
|                         Timber.e("Contribution already exists"); | ||||
|                         compositeDisposable.add(contributionsRepository | ||||
|                             .deleteContributionFromDB(it) | ||||
|                             .subscribeOn(ioThreadScheduler).doOnComplete(() -> { | ||||
|                                 restartUploads(contributionList, index + 1, context); | ||||
|                             }) | ||||
|                             .subscribe()); | ||||
|                     } | ||||
|                 }, throwable -> { | ||||
|                     Timber.e(throwable); | ||||
|                     restartUploads(contributionList, index + 1, context); | ||||
|                 } | ||||
|             )); | ||||
|                 })); | ||||
|         } else { | ||||
|             it.setState(Contribution.STATE_QUEUED); | ||||
|             compositeDisposable.add(contributionsRepository | ||||
|                 .save(it) | ||||
|                 .subscribeOn(ioThreadScheduler) | ||||
|                 .doOnComplete(() -> { | ||||
|                     restartUploads(contributionList, index + 1, context); | ||||
|                 }) | ||||
|                 .subscribe()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void restartUpload(List<Contribution> contributionList, int index, Context context) { | ||||
|  | @ -167,18 +192,31 @@ public class PendingUploadsPresenter implements UserActionListener { | |||
|                 it.setChunkInfo(null); | ||||
|                 it.setTransferred(0); | ||||
|             } | ||||
|             compositeDisposable.add(uploadRepository | ||||
|                 .checkDuplicateImage(it.getLocalUriPath().getPath()) | ||||
|                 .subscribeOn(ioThreadScheduler) | ||||
|                 .subscribe(imageCheckResult -> { | ||||
|                     if (imageCheckResult == IMAGE_OK) { | ||||
|                         it.setState(Contribution.STATE_QUEUED); | ||||
|                         compositeDisposable.add(contributionsRepository | ||||
|                             .save(it) | ||||
|                             .subscribeOn(ioThreadScheduler) | ||||
|                             .subscribe()); | ||||
|                     }else { | ||||
|                         Timber.e("Contribution already exists"); | ||||
|                         compositeDisposable.add(contributionsRepository | ||||
|                             .deleteContributionFromDB(it) | ||||
|                             .subscribeOn(ioThreadScheduler) | ||||
|                             .subscribe()); | ||||
|                     } | ||||
|                 })); | ||||
|         } else { | ||||
|             it.setState(Contribution.STATE_QUEUED); | ||||
|             compositeDisposable.add(contributionsRepository | ||||
|                 .save(it) | ||||
|                 .subscribeOn(ioThreadScheduler) | ||||
|                 .subscribe()); | ||||
|         } | ||||
|         it.setState(Contribution.STATE_QUEUED); | ||||
|         compositeDisposable.add(repository | ||||
|             .save(it) | ||||
|             .subscribeOn(ioThreadScheduler) | ||||
|             .subscribe(() -> | ||||
|                     WorkRequestHelper.Companion.makeOneTimeWorkRequest( | ||||
|                         context, ExistingWorkPolicy.KEEP), | ||||
|                 throwable -> { | ||||
|                     Timber.e(throwable); | ||||
|                 } | ||||
|             )); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -103,6 +103,16 @@ public class UploadModel { | |||
|         return imageProcessingService.validateImage(uploadItem, inAppPictureLocation); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Calls checkDuplicateImage() of ImageProcessingService to check if image is duplicate | ||||
|      * | ||||
|      * @param filePath file to be checked | ||||
|      * @return IMAGE_DUPLICATE or IMAGE_OK | ||||
|      */ | ||||
|     public Single<Integer> checkDuplicateImage(String filePath){ | ||||
|         return imageProcessingService.checkDuplicateImage(filePath); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Calls validateCaption() of ImageProcessingService to check caption of image | ||||
|      * | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Kanahia
						Kanahia