mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-31 06:43:56 +01:00 
			
		
		
		
	* Edited Project.xml to make indent size 4 * Changed files with 2 space indentation to use 4 space indentation * Edited Project.xml to make indent size 4 * changed files with 2 space indent to 4 space indent * fix :Back Pressed Event not work in Explore tab when user not login (#4404) * fix :Back Pressed Event not work in Explore tab * minor changes * fix :Upload count or number of contribution does not get updated when media is successful uploaded (#4399) * * fix:Number of Contributions not updated * Add javadocs * minor changes * made minor changes * String was nonsense and untranslatible, fixed (#4466) * Ability to show captions and descriptions in all entered languages (#4355) * implement Ability to show captions and descriptions in all entered languages *Add Javadoc * handle Back event of fragment(mediaDetailFragment) * fix minor bugs * add internationalization * revert previous changes * fix visibility bug * resolve conflict Co-authored-by: Prince kushwaha <65972015+Prince-kushwaha@users.noreply.github.com> Co-authored-by: neslihanturan <tur.neslihan@gmail.com>
This commit is contained in:
		
							parent
							
								
									b202f553f0
								
							
						
					
					
						commit
						ca9f6f5e47
					
				
					 36 changed files with 3047 additions and 2988 deletions
				
			
		|  | @ -18,61 +18,61 @@ import java.util.List; | |||
| @Dao | ||||
| public abstract class ContributionDao { | ||||
| 
 | ||||
|   @Query("SELECT * FROM contribution order by media_dateUploaded DESC") | ||||
|   abstract DataSource.Factory<Integer, Contribution> fetchContributions(); | ||||
|     @Query("SELECT * FROM contribution order by media_dateUploaded DESC") | ||||
|     abstract DataSource.Factory<Integer, Contribution> fetchContributions(); | ||||
| 
 | ||||
|   @Insert(onConflict = OnConflictStrategy.REPLACE) | ||||
|   public abstract void saveSynchronous(Contribution contribution); | ||||
|     @Insert(onConflict = OnConflictStrategy.REPLACE) | ||||
|     public abstract void saveSynchronous(Contribution contribution); | ||||
| 
 | ||||
|   public Completable save(final Contribution contribution) { | ||||
|     return Completable | ||||
|         .fromAction(() -> { | ||||
|           contribution.setDateModified(Calendar.getInstance().getTime()); | ||||
|           saveSynchronous(contribution); | ||||
|         }); | ||||
|   } | ||||
|     public Completable save(final Contribution contribution) { | ||||
|         return Completable | ||||
|             .fromAction(() -> { | ||||
|                 contribution.setDateModified(Calendar.getInstance().getTime()); | ||||
|                 saveSynchronous(contribution); | ||||
|             }); | ||||
|     } | ||||
| 
 | ||||
|   @Transaction | ||||
|   public void deleteAndSaveContribution(final Contribution oldContribution, | ||||
|       final Contribution newContribution) { | ||||
|     deleteSynchronous(oldContribution); | ||||
|     saveSynchronous(newContribution); | ||||
|   } | ||||
|     @Transaction | ||||
|     public void deleteAndSaveContribution(final Contribution oldContribution, | ||||
|         final Contribution newContribution) { | ||||
|         deleteSynchronous(oldContribution); | ||||
|         saveSynchronous(newContribution); | ||||
|     } | ||||
| 
 | ||||
|   @Insert(onConflict = OnConflictStrategy.REPLACE) | ||||
|   public abstract Single<List<Long>> save(List<Contribution> contribution); | ||||
|     @Insert(onConflict = OnConflictStrategy.REPLACE) | ||||
|     public abstract Single<List<Long>> save(List<Contribution> contribution); | ||||
| 
 | ||||
|   @Delete | ||||
|   public abstract void deleteSynchronous(Contribution contribution); | ||||
|     @Delete | ||||
|     public abstract void deleteSynchronous(Contribution contribution); | ||||
| 
 | ||||
|   public Completable delete(final Contribution contribution) { | ||||
|     return Completable | ||||
|         .fromAction(() -> deleteSynchronous(contribution)); | ||||
|   } | ||||
|     public Completable delete(final Contribution contribution) { | ||||
|         return Completable | ||||
|             .fromAction(() -> deleteSynchronous(contribution)); | ||||
|     } | ||||
| 
 | ||||
|   @Query("SELECT * from contribution WHERE media_filename=:fileName") | ||||
|   public abstract List<Contribution> getContributionWithTitle(String fileName); | ||||
|     @Query("SELECT * from contribution WHERE media_filename=:fileName") | ||||
|     public abstract List<Contribution> getContributionWithTitle(String fileName); | ||||
| 
 | ||||
|   @Query("SELECT * from contribution WHERE pageId=:pageId") | ||||
|   public abstract Contribution getContribution(String pageId); | ||||
|     @Query("SELECT * from contribution WHERE pageId=:pageId") | ||||
|     public abstract Contribution getContribution(String pageId); | ||||
| 
 | ||||
|   @Query("SELECT * from contribution WHERE state IN (:states) order by media_dateUploaded DESC") | ||||
|   public abstract Single<List<Contribution>> getContribution(List<Integer> states); | ||||
|     @Query("SELECT * from contribution WHERE state IN (:states) order by media_dateUploaded DESC") | ||||
|     public abstract Single<List<Contribution>> getContribution(List<Integer> states); | ||||
| 
 | ||||
|   @Query("SELECT COUNT(*) from contribution WHERE state in (:toUpdateStates)") | ||||
|   public abstract Single<Integer> getPendingUploads(int[] toUpdateStates); | ||||
|     @Query("SELECT COUNT(*) from contribution WHERE state in (:toUpdateStates)") | ||||
|     public abstract Single<Integer> getPendingUploads(int[] toUpdateStates); | ||||
| 
 | ||||
|   @Query("Delete FROM contribution") | ||||
|   public abstract void deleteAll() throws SQLiteException; | ||||
|     @Query("Delete FROM contribution") | ||||
|     public abstract void deleteAll() throws SQLiteException; | ||||
| 
 | ||||
|   @Update | ||||
|   public abstract void updateSynchronous(Contribution contribution); | ||||
|     @Update | ||||
|     public abstract void updateSynchronous(Contribution contribution); | ||||
| 
 | ||||
|   public Completable update(final Contribution contribution) { | ||||
|     return Completable | ||||
|         .fromAction(() -> { | ||||
|           contribution.setDateModified(Calendar.getInstance().getTime()); | ||||
|           updateSynchronous(contribution); | ||||
|         }); | ||||
|   } | ||||
|     public Completable update(final Contribution contribution) { | ||||
|         return Completable | ||||
|             .fromAction(() -> { | ||||
|                 contribution.setDateModified(Calendar.getInstance().getTime()); | ||||
|                 updateSynchronous(contribution); | ||||
|             }); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -24,244 +24,243 @@ import io.reactivex.schedulers.Schedulers; | |||
| 
 | ||||
| public class ContributionViewHolder extends RecyclerView.ViewHolder { | ||||
| 
 | ||||
|   private final Callback callback; | ||||
|   @BindView(R.id.contributionImage) | ||||
|   SimpleDraweeView imageView; | ||||
|   @BindView(R.id.contributionTitle) | ||||
|   TextView titleView; | ||||
|   @BindView(R.id.authorView) | ||||
|   TextView authorView; | ||||
|   @BindView(R.id.contributionState) | ||||
|   TextView stateView; | ||||
|   @BindView(R.id.contributionSequenceNumber) | ||||
|   TextView seqNumView; | ||||
|   @BindView(R.id.contributionProgress) | ||||
|   ProgressBar progressView; | ||||
|   @BindView(R.id.image_options) | ||||
|   RelativeLayout imageOptions; | ||||
|   @BindView(R.id.wikipediaButton) | ||||
|   ImageButton addToWikipediaButton; | ||||
|   @BindView(R.id.retryButton) | ||||
|   ImageButton retryButton; | ||||
|   @BindView(R.id.cancelButton) | ||||
|   ImageButton cancelButton; | ||||
|   @BindView(R.id.pauseResumeButton) | ||||
|   ImageButton pauseResumeButton; | ||||
|     private final Callback callback; | ||||
|     @BindView(R.id.contributionImage) | ||||
|     SimpleDraweeView imageView; | ||||
|     @BindView(R.id.contributionTitle) | ||||
|     TextView titleView; | ||||
|     @BindView(R.id.authorView) | ||||
|     TextView authorView; | ||||
|     @BindView(R.id.contributionState) | ||||
|     TextView stateView; | ||||
|     @BindView(R.id.contributionSequenceNumber) | ||||
|     TextView seqNumView; | ||||
|     @BindView(R.id.contributionProgress) | ||||
|     ProgressBar progressView; | ||||
|     @BindView(R.id.image_options) | ||||
|     RelativeLayout imageOptions; | ||||
|     @BindView(R.id.wikipediaButton) | ||||
|     ImageButton addToWikipediaButton; | ||||
|     @BindView(R.id.retryButton) | ||||
|     ImageButton retryButton; | ||||
|     @BindView(R.id.cancelButton) | ||||
|     ImageButton cancelButton; | ||||
|     @BindView(R.id.pauseResumeButton) | ||||
|     ImageButton pauseResumeButton; | ||||
| 
 | ||||
| 
 | ||||
|   private int position; | ||||
|   private Contribution contribution; | ||||
|   private final CompositeDisposable compositeDisposable = new CompositeDisposable(); | ||||
|   private final MediaClient mediaClient; | ||||
|   private boolean isWikipediaButtonDisplayed; | ||||
|     private int position; | ||||
|     private Contribution contribution; | ||||
|     private final CompositeDisposable compositeDisposable = new CompositeDisposable(); | ||||
|     private final MediaClient mediaClient; | ||||
|     private boolean isWikipediaButtonDisplayed; | ||||
| 
 | ||||
|   ContributionViewHolder(final View parent, final Callback callback, | ||||
|       final MediaClient mediaClient) { | ||||
|     super(parent); | ||||
|     this.mediaClient = mediaClient; | ||||
|     ButterKnife.bind(this, parent); | ||||
|     this.callback = callback; | ||||
|   } | ||||
| 
 | ||||
|   public void init(final int position, final Contribution contribution) { | ||||
| 
 | ||||
|     //handling crashes when the contribution is null. | ||||
|     if( null == contribution) { | ||||
|       return; | ||||
|     ContributionViewHolder(final View parent, final Callback callback, | ||||
|         final MediaClient mediaClient) { | ||||
|         super(parent); | ||||
|         this.mediaClient = mediaClient; | ||||
|         ButterKnife.bind(this, parent); | ||||
|         this.callback = callback; | ||||
|     } | ||||
| 
 | ||||
|     this.contribution = contribution; | ||||
|     this.position = position; | ||||
|     titleView.setText(contribution.getMedia().getMostRelevantCaption()); | ||||
|     authorView.setText(contribution.getMedia().getAuthor()); | ||||
|     public void init(final int position, final Contribution contribution) { | ||||
| 
 | ||||
|     //Removes flicker of loading image. | ||||
|     imageView.getHierarchy().setFadeDuration(0); | ||||
| 
 | ||||
|     imageView.getHierarchy().setPlaceholderImage(R.drawable.image_placeholder); | ||||
|     imageView.getHierarchy().setFailureImage(R.drawable.image_placeholder); | ||||
| 
 | ||||
| 
 | ||||
|     final String imageSource = chooseImageSource(contribution.getMedia().getThumbUrl(), | ||||
|         contribution.getLocalUri()); | ||||
|     if (!TextUtils.isEmpty(imageSource)) { | ||||
|       final ImageRequest imageRequest = | ||||
|           ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageSource)) | ||||
|               .setProgressiveRenderingEnabled(true) | ||||
|               .build(); | ||||
|       imageView.setImageRequest(imageRequest); | ||||
|     } | ||||
| 
 | ||||
|     seqNumView.setText(String.valueOf(position + 1)); | ||||
|     seqNumView.setVisibility(View.VISIBLE); | ||||
| 
 | ||||
|     addToWikipediaButton.setVisibility(View.GONE); | ||||
|     switch (contribution.getState()) { | ||||
|       case Contribution.STATE_COMPLETED: | ||||
|         stateView.setVisibility(View.GONE); | ||||
|         progressView.setVisibility(View.GONE); | ||||
|         imageOptions.setVisibility(View.GONE); | ||||
|         stateView.setText(""); | ||||
|         checkIfMediaExistsOnWikipediaPage(contribution); | ||||
|         break; | ||||
|       case Contribution.STATE_QUEUED: | ||||
|       case Contribution.STATE_QUEUED_LIMITED_CONNECTION_MODE: | ||||
|         stateView.setVisibility(View.VISIBLE); | ||||
|         progressView.setVisibility(View.GONE); | ||||
|         stateView.setText(R.string.contribution_state_queued); | ||||
|         imageOptions.setVisibility(View.GONE); | ||||
|         break; | ||||
|       case Contribution.STATE_IN_PROGRESS: | ||||
|         stateView.setVisibility(View.GONE); | ||||
|         progressView.setVisibility(View.VISIBLE); | ||||
|         addToWikipediaButton.setVisibility(View.GONE); | ||||
|         pauseResumeButton.setVisibility(View.VISIBLE); | ||||
|         cancelButton.setVisibility(View.GONE); | ||||
|         retryButton.setVisibility(View.GONE); | ||||
|         imageOptions.setVisibility(View.VISIBLE); | ||||
|         final long total = contribution.getDataLength(); | ||||
|         final long transferred = contribution.getTransferred(); | ||||
|         if (transferred == 0 || transferred >= total) { | ||||
|           progressView.setIndeterminate(true); | ||||
|         } else { | ||||
|           progressView.setProgress((int) (((double) transferred / (double) total) * 100)); | ||||
|         //handling crashes when the contribution is null. | ||||
|         if (null == contribution) { | ||||
|             return; | ||||
|         } | ||||
|         break; | ||||
|       case Contribution.STATE_PAUSED: | ||||
|         stateView.setVisibility(View.VISIBLE); | ||||
|         stateView.setText(R.string.paused); | ||||
| 
 | ||||
|         this.contribution = contribution; | ||||
|         this.position = position; | ||||
|         titleView.setText(contribution.getMedia().getMostRelevantCaption()); | ||||
|         authorView.setText(contribution.getMedia().getAuthor()); | ||||
| 
 | ||||
|         //Removes flicker of loading image. | ||||
|         imageView.getHierarchy().setFadeDuration(0); | ||||
| 
 | ||||
|         imageView.getHierarchy().setPlaceholderImage(R.drawable.image_placeholder); | ||||
|         imageView.getHierarchy().setFailureImage(R.drawable.image_placeholder); | ||||
| 
 | ||||
|         final String imageSource = chooseImageSource(contribution.getMedia().getThumbUrl(), | ||||
|             contribution.getLocalUri()); | ||||
|         if (!TextUtils.isEmpty(imageSource)) { | ||||
|             final ImageRequest imageRequest = | ||||
|                 ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageSource)) | ||||
|                     .setProgressiveRenderingEnabled(true) | ||||
|                     .build(); | ||||
|             imageView.setImageRequest(imageRequest); | ||||
|         } | ||||
| 
 | ||||
|         seqNumView.setText(String.valueOf(position + 1)); | ||||
|         seqNumView.setVisibility(View.VISIBLE); | ||||
| 
 | ||||
|         addToWikipediaButton.setVisibility(View.GONE); | ||||
|         switch (contribution.getState()) { | ||||
|             case Contribution.STATE_COMPLETED: | ||||
|                 stateView.setVisibility(View.GONE); | ||||
|                 progressView.setVisibility(View.GONE); | ||||
|                 imageOptions.setVisibility(View.GONE); | ||||
|                 stateView.setText(""); | ||||
|                 checkIfMediaExistsOnWikipediaPage(contribution); | ||||
|                 break; | ||||
|             case Contribution.STATE_QUEUED: | ||||
|             case Contribution.STATE_QUEUED_LIMITED_CONNECTION_MODE: | ||||
|                 stateView.setVisibility(View.VISIBLE); | ||||
|                 progressView.setVisibility(View.GONE); | ||||
|                 stateView.setText(R.string.contribution_state_queued); | ||||
|                 imageOptions.setVisibility(View.GONE); | ||||
|                 break; | ||||
|             case Contribution.STATE_IN_PROGRESS: | ||||
|                 stateView.setVisibility(View.GONE); | ||||
|                 progressView.setVisibility(View.VISIBLE); | ||||
|                 addToWikipediaButton.setVisibility(View.GONE); | ||||
|                 pauseResumeButton.setVisibility(View.VISIBLE); | ||||
|                 cancelButton.setVisibility(View.GONE); | ||||
|                 retryButton.setVisibility(View.GONE); | ||||
|                 imageOptions.setVisibility(View.VISIBLE); | ||||
|                 final long total = contribution.getDataLength(); | ||||
|                 final long transferred = contribution.getTransferred(); | ||||
|                 if (transferred == 0 || transferred >= total) { | ||||
|                     progressView.setIndeterminate(true); | ||||
|                 } else { | ||||
|                     progressView.setProgress((int) (((double) transferred / (double) total) * 100)); | ||||
|                 } | ||||
|                 break; | ||||
|             case Contribution.STATE_PAUSED: | ||||
|                 stateView.setVisibility(View.VISIBLE); | ||||
|                 stateView.setText(R.string.paused); | ||||
|                 setResume(); | ||||
|                 progressView.setVisibility(View.GONE); | ||||
|                 cancelButton.setVisibility(View.GONE); | ||||
|                 retryButton.setVisibility(View.GONE); | ||||
|                 pauseResumeButton.setVisibility(View.VISIBLE); | ||||
|                 imageOptions.setVisibility(View.VISIBLE); | ||||
|                 break; | ||||
|             case Contribution.STATE_FAILED: | ||||
|                 stateView.setVisibility(View.VISIBLE); | ||||
|                 stateView.setText(R.string.contribution_state_failed); | ||||
|                 progressView.setVisibility(View.GONE); | ||||
|                 cancelButton.setVisibility(View.VISIBLE); | ||||
|                 retryButton.setVisibility(View.VISIBLE); | ||||
|                 pauseResumeButton.setVisibility(View.GONE); | ||||
|                 imageOptions.setVisibility(View.VISIBLE); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Checks if a media exists on the corresponding Wikipedia article Currently the check is made | ||||
|      * for the device's current language Wikipedia | ||||
|      * | ||||
|      * @param contribution | ||||
|      */ | ||||
|     private void checkIfMediaExistsOnWikipediaPage(final Contribution contribution) { | ||||
|         if (contribution.getWikidataPlace() == null | ||||
|             || contribution.getWikidataPlace().getWikipediaArticle() == null) { | ||||
|             return; | ||||
|         } | ||||
|         final String wikipediaArticle = contribution.getWikidataPlace().getWikipediaPageTitle(); | ||||
|         compositeDisposable.add(mediaClient.doesPageContainMedia(wikipediaArticle) | ||||
|             .subscribeOn(Schedulers.io()) | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
|             .subscribe(mediaExists -> { | ||||
|                 displayWikipediaButton(mediaExists); | ||||
|             })); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Handle action buttons visibility if the corresponding wikipedia page doesn't contain any | ||||
|      * media. This method needs to control the state of just the scenario where media does not | ||||
|      * exists as other scenarios are already handled in the init method. | ||||
|      * | ||||
|      * @param mediaExists | ||||
|      */ | ||||
|     private void displayWikipediaButton(Boolean mediaExists) { | ||||
|         if (!mediaExists) { | ||||
|             addToWikipediaButton.setVisibility(View.VISIBLE); | ||||
|             isWikipediaButtonDisplayed = true; | ||||
|             cancelButton.setVisibility(View.GONE); | ||||
|             retryButton.setVisibility(View.GONE); | ||||
|             imageOptions.setVisibility(View.VISIBLE); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the image source for the image view, first preference is given to thumbUrl if that is | ||||
|      * null, moves to local uri and if both are null return null | ||||
|      * | ||||
|      * @param thumbUrl | ||||
|      * @param localUri | ||||
|      * @return | ||||
|      */ | ||||
|     @Nullable | ||||
|     private String chooseImageSource(final String thumbUrl, final Uri localUri) { | ||||
|         return !TextUtils.isEmpty(thumbUrl) ? thumbUrl : | ||||
|             localUri != null ? localUri.toString() : | ||||
|                 null; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Retry upload when it is failed | ||||
|      */ | ||||
|     @OnClick(R.id.retryButton) | ||||
|     public void retryUpload() { | ||||
|         callback.retryUpload(contribution); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Delete a failed upload attempt | ||||
|      */ | ||||
|     @OnClick(R.id.cancelButton) | ||||
|     public void deleteUpload() { | ||||
|         callback.deleteUpload(contribution); | ||||
|     } | ||||
| 
 | ||||
|     @OnClick(R.id.contributionImage) | ||||
|     public void imageClicked() { | ||||
|         callback.openMediaDetail(position, isWikipediaButtonDisplayed); | ||||
|     } | ||||
| 
 | ||||
|     @OnClick(R.id.wikipediaButton) | ||||
|     public void wikipediaButtonClicked() { | ||||
|         callback.addImageToWikipedia(contribution); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Triggers a callback for pause/resume | ||||
|      */ | ||||
|     @OnClick(R.id.pauseResumeButton) | ||||
|     public void onPauseResumeButtonClicked() { | ||||
|         if (pauseResumeButton.getTag().toString().equals("pause")) { | ||||
|             pause(); | ||||
|         } else { | ||||
|             resume(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void resume() { | ||||
|         callback.resumeUpload(contribution); | ||||
|         setPaused(); | ||||
|     } | ||||
| 
 | ||||
|     private void pause() { | ||||
|         callback.pauseUpload(contribution); | ||||
|         setResume(); | ||||
|         progressView.setVisibility(View.GONE); | ||||
|         cancelButton.setVisibility(View.GONE); | ||||
|         retryButton.setVisibility(View.GONE); | ||||
|         pauseResumeButton.setVisibility(View.VISIBLE); | ||||
|         imageOptions.setVisibility(View.VISIBLE); | ||||
|         break; | ||||
|       case Contribution.STATE_FAILED: | ||||
|         stateView.setVisibility(View.VISIBLE); | ||||
|         stateView.setText(R.string.contribution_state_failed); | ||||
|         progressView.setVisibility(View.GONE); | ||||
|         cancelButton.setVisibility(View.VISIBLE); | ||||
|         retryButton.setVisibility(View.VISIBLE); | ||||
|         pauseResumeButton.setVisibility(View.GONE); | ||||
|         imageOptions.setVisibility(View.VISIBLE); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Checks if a media exists on the corresponding Wikipedia article Currently the check is made for | ||||
|    * the device's current language Wikipedia | ||||
|    * | ||||
|    * @param contribution | ||||
|    */ | ||||
|   private void checkIfMediaExistsOnWikipediaPage(final Contribution contribution) { | ||||
|     if (contribution.getWikidataPlace() == null | ||||
|         || contribution.getWikidataPlace().getWikipediaArticle() == null) { | ||||
|       return; | ||||
|     /** | ||||
|      * Update pause/resume button to show pause state | ||||
|      */ | ||||
|     private void setPaused() { | ||||
|         pauseResumeButton.setImageResource(R.drawable.pause_icon); | ||||
|         pauseResumeButton.setTag(R.string.pause); | ||||
|     } | ||||
|     final String wikipediaArticle = contribution.getWikidataPlace().getWikipediaPageTitle(); | ||||
|     compositeDisposable.add(mediaClient.doesPageContainMedia(wikipediaArticle) | ||||
|         .subscribeOn(Schedulers.io()) | ||||
|         .observeOn(AndroidSchedulers.mainThread()) | ||||
|         .subscribe(mediaExists -> { | ||||
|           displayWikipediaButton(mediaExists); | ||||
|         })); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Handle action buttons visibility if the corresponding wikipedia page doesn't contain any media. | ||||
|    * This method needs to control the state of just the scenario where media does not exists as | ||||
|    * other scenarios are already handled in the init method. | ||||
|    * | ||||
|    * @param mediaExists | ||||
|    */ | ||||
|   private void displayWikipediaButton(Boolean mediaExists) { | ||||
|     if (!mediaExists) { | ||||
|       addToWikipediaButton.setVisibility(View.VISIBLE); | ||||
|       isWikipediaButtonDisplayed = true; | ||||
|       cancelButton.setVisibility(View.GONE); | ||||
|       retryButton.setVisibility(View.GONE); | ||||
|       imageOptions.setVisibility(View.VISIBLE); | ||||
|     /** | ||||
|      * Update pause/resume button to show resume state | ||||
|      */ | ||||
|     private void setResume() { | ||||
|         pauseResumeButton.setImageResource(R.drawable.play_icon); | ||||
|         pauseResumeButton.setTag(R.string.resume); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the image source for the image view, first preference is given to thumbUrl if that is | ||||
|    * null, moves to local uri and if both are null return null | ||||
|    * | ||||
|    * @param thumbUrl | ||||
|    * @param localUri | ||||
|    * @return | ||||
|    */ | ||||
|   @Nullable | ||||
|   private String chooseImageSource(final String thumbUrl, final Uri localUri) { | ||||
|     return !TextUtils.isEmpty(thumbUrl) ? thumbUrl : | ||||
|         localUri != null ? localUri.toString() : | ||||
|             null; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Retry upload when it is failed | ||||
|    */ | ||||
|   @OnClick(R.id.retryButton) | ||||
|   public void retryUpload() { | ||||
|     callback.retryUpload(contribution); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Delete a failed upload attempt | ||||
|    */ | ||||
|   @OnClick(R.id.cancelButton) | ||||
|   public void deleteUpload() { | ||||
|     callback.deleteUpload(contribution); | ||||
|   } | ||||
| 
 | ||||
|   @OnClick(R.id.contributionImage) | ||||
|   public void imageClicked() { | ||||
|     callback.openMediaDetail(position, isWikipediaButtonDisplayed); | ||||
|   } | ||||
| 
 | ||||
|   @OnClick(R.id.wikipediaButton) | ||||
|   public void wikipediaButtonClicked() { | ||||
|     callback.addImageToWikipedia(contribution); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Triggers a callback for pause/resume | ||||
|    */ | ||||
|   @OnClick(R.id.pauseResumeButton) | ||||
|   public void onPauseResumeButtonClicked() { | ||||
|     if (pauseResumeButton.getTag().toString().equals("pause")) { | ||||
|       pause(); | ||||
|     } else { | ||||
|       resume(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private void resume() { | ||||
|     callback.resumeUpload(contribution); | ||||
|     setPaused(); | ||||
|   } | ||||
| 
 | ||||
|   private void pause() { | ||||
|     callback.pauseUpload(contribution); | ||||
|     setResume(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Update pause/resume button to show pause state | ||||
|    */ | ||||
|   private void setPaused() { | ||||
|     pauseResumeButton.setImageResource(R.drawable.pause_icon); | ||||
|     pauseResumeButton.setTag(R.string.pause); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Update pause/resume button to show resume state | ||||
|    */ | ||||
|   private void setResume() { | ||||
|     pauseResumeButton.setImageResource(R.drawable.play_icon); | ||||
|     pauseResumeButton.setTag(R.string.resume); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -8,17 +8,17 @@ import java.util.List; | |||
|  */ | ||||
| public class ContributionsListContract { | ||||
| 
 | ||||
|   public interface View { | ||||
|     public interface View { | ||||
| 
 | ||||
|     void showWelcomeTip(boolean numberOfUploads); | ||||
|         void showWelcomeTip(boolean numberOfUploads); | ||||
| 
 | ||||
|     void showProgress(boolean shouldShow); | ||||
|         void showProgress(boolean shouldShow); | ||||
| 
 | ||||
|     void showNoContributionsUI(boolean shouldShow); | ||||
|   } | ||||
|         void showNoContributionsUI(boolean shouldShow); | ||||
|     } | ||||
| 
 | ||||
|   public interface UserActionListener extends BasePresenter<View> { | ||||
|     public interface UserActionListener extends BasePresenter<View> { | ||||
| 
 | ||||
|     void deleteUpload(Contribution contribution); | ||||
|   } | ||||
|         void deleteUpload(Contribution contribution); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -51,384 +51,388 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl | |||
|     ContributionsListContract.View, ContributionsListAdapter.Callback, | ||||
|     WikipediaInstructionsDialogFragment.Callback { | ||||
| 
 | ||||
|   private static final String RV_STATE = "rv_scroll_state"; | ||||
|     private static final String RV_STATE = "rv_scroll_state"; | ||||
| 
 | ||||
|   @BindView(R.id.contributionsList) | ||||
|   RecyclerView rvContributionsList; | ||||
|   @BindView(R.id.loadingContributionsProgressBar) | ||||
|   ProgressBar progressBar; | ||||
|   @BindView(R.id.fab_plus) | ||||
|   FloatingActionButton fabPlus; | ||||
|   @BindView(R.id.fab_camera) | ||||
|   FloatingActionButton fabCamera; | ||||
|   @BindView(R.id.fab_gallery) | ||||
|   FloatingActionButton fabGallery; | ||||
|   @BindView(R.id.noContributionsYet) | ||||
|   TextView noContributionsYet; | ||||
|   @BindView(R.id.fab_layout) | ||||
|   LinearLayout fab_layout; | ||||
|     @BindView(R.id.contributionsList) | ||||
|     RecyclerView rvContributionsList; | ||||
|     @BindView(R.id.loadingContributionsProgressBar) | ||||
|     ProgressBar progressBar; | ||||
|     @BindView(R.id.fab_plus) | ||||
|     FloatingActionButton fabPlus; | ||||
|     @BindView(R.id.fab_camera) | ||||
|     FloatingActionButton fabCamera; | ||||
|     @BindView(R.id.fab_gallery) | ||||
|     FloatingActionButton fabGallery; | ||||
|     @BindView(R.id.noContributionsYet) | ||||
|     TextView noContributionsYet; | ||||
|     @BindView(R.id.fab_layout) | ||||
|     LinearLayout fab_layout; | ||||
| 
 | ||||
|   @Inject | ||||
|   ContributionController controller; | ||||
|   @Inject | ||||
|   MediaClient mediaClient; | ||||
|     @Inject | ||||
|     ContributionController controller; | ||||
|     @Inject | ||||
|     MediaClient mediaClient; | ||||
| 
 | ||||
|   @Named(NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE) | ||||
|   @Inject | ||||
|   WikiSite languageWikipediaSite; | ||||
|     @Named(NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE) | ||||
|     @Inject | ||||
|     WikiSite languageWikipediaSite; | ||||
| 
 | ||||
|   @Inject | ||||
|   ContributionsListPresenter contributionsListPresenter; | ||||
|     @Inject | ||||
|     ContributionsListPresenter contributionsListPresenter; | ||||
| 
 | ||||
|   private Animation fab_close; | ||||
|   private Animation fab_open; | ||||
|   private Animation rotate_forward; | ||||
|   private Animation rotate_backward; | ||||
|     private Animation fab_close; | ||||
|     private Animation fab_open; | ||||
|     private Animation rotate_forward; | ||||
|     private Animation rotate_backward; | ||||
| 
 | ||||
| 
 | ||||
|   private boolean isFabOpen; | ||||
|     private boolean isFabOpen; | ||||
| 
 | ||||
|   private ContributionsListAdapter adapter; | ||||
|     private ContributionsListAdapter adapter; | ||||
| 
 | ||||
|   private Callback callback; | ||||
|     private Callback callback; | ||||
| 
 | ||||
|   private final int SPAN_COUNT_LANDSCAPE = 3; | ||||
|   private final int SPAN_COUNT_PORTRAIT = 1; | ||||
|     private final int SPAN_COUNT_LANDSCAPE = 3; | ||||
|     private final int SPAN_COUNT_PORTRAIT = 1; | ||||
| 
 | ||||
|   private int contributionsSize; | ||||
|     private int contributionsSize; | ||||
| 
 | ||||
| 
 | ||||
|   @Override | ||||
|   public View onCreateView( | ||||
|       final LayoutInflater inflater, @Nullable final ViewGroup container, | ||||
|       @Nullable final Bundle savedInstanceState) { | ||||
|     final View view = inflater.inflate(R.layout.fragment_contributions_list, container, false); | ||||
|     ButterKnife.bind(this, view); | ||||
|     contributionsListPresenter.onAttachView(this); | ||||
|     initAdapter(); | ||||
|     return view; | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void onAttach(Context context) { | ||||
|     super.onAttach(context); | ||||
|     if (getParentFragment() != null && getParentFragment() instanceof ContributionsFragment) { | ||||
|       callback = ((ContributionsFragment) getParentFragment()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void onDetach() { | ||||
|     super.onDetach(); | ||||
|     callback = null;//To avoid possible memory leak | ||||
|   } | ||||
| 
 | ||||
|   private void initAdapter() { | ||||
|     adapter = new ContributionsListAdapter(this, mediaClient); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void onViewCreated(final View view, @Nullable final Bundle savedInstanceState) { | ||||
|     super.onViewCreated(view, savedInstanceState); | ||||
|     initRecyclerView(); | ||||
|     initializeAnimations(); | ||||
|     setListeners(); | ||||
|   } | ||||
| 
 | ||||
|   private void initRecyclerView() { | ||||
|     final GridLayoutManager layoutManager = new GridLayoutManager(getContext(), | ||||
|         getSpanCount(getResources().getConfiguration().orientation)); | ||||
|     rvContributionsList.setLayoutManager(layoutManager); | ||||
| 
 | ||||
|     //Setting flicker animation of recycler view to false. | ||||
|     final ItemAnimator animator = rvContributionsList.getItemAnimator(); | ||||
|     if (animator instanceof SimpleItemAnimator) { | ||||
|       ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false); | ||||
|     @Override | ||||
|     public View onCreateView( | ||||
|         final LayoutInflater inflater, @Nullable final ViewGroup container, | ||||
|         @Nullable final Bundle savedInstanceState) { | ||||
|         final View view = inflater.inflate(R.layout.fragment_contributions_list, container, false); | ||||
|         ButterKnife.bind(this, view); | ||||
|         contributionsListPresenter.onAttachView(this); | ||||
|         initAdapter(); | ||||
|         return view; | ||||
|     } | ||||
| 
 | ||||
|     contributionsListPresenter.setup(); | ||||
|     contributionsListPresenter.contributionList.observe(this.getViewLifecycleOwner(), list -> { | ||||
|       contributionsSize = list.size(); | ||||
|       adapter.submitList(list); | ||||
|       callback.notifyDataSetChanged(); | ||||
|     }); | ||||
|     rvContributionsList.setAdapter(adapter); | ||||
|     adapter.registerAdapterDataObserver(new AdapterDataObserver() { | ||||
|       @Override | ||||
|       public void onItemRangeInserted(int positionStart, int itemCount) { | ||||
|         super.onItemRangeInserted(positionStart, itemCount); | ||||
|         if (itemCount > 0 && positionStart == 0) { | ||||
|           if(adapter.getContributionForPosition(positionStart)!=null) { | ||||
|             rvContributionsList.scrollToPosition(0);//Newly upload items are always added to the top | ||||
|           } | ||||
|     @Override | ||||
|     public void onAttach(Context context) { | ||||
|         super.onAttach(context); | ||||
|         if (getParentFragment() != null && getParentFragment() instanceof ContributionsFragment) { | ||||
|             callback = ((ContributionsFragment) getParentFragment()); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|       /** | ||||
|        * Called whenever items in the list have changed | ||||
|        * Calls viewPagerNotifyDataSetChanged() that will notify the viewpager | ||||
|        */ | ||||
|       @Override | ||||
|       public void onItemRangeChanged(final int positionStart, final int itemCount) { | ||||
|         super.onItemRangeChanged(positionStart, itemCount); | ||||
|         callback.viewPagerNotifyDataSetChanged(); | ||||
|       } | ||||
|     }); | ||||
|     @Override | ||||
|     public void onDetach() { | ||||
|         super.onDetach(); | ||||
|         callback = null;//To avoid possible memory leak | ||||
|     } | ||||
| 
 | ||||
|     //Fab close on touch outside (Scrolling or taping on item triggers this action). | ||||
|     rvContributionsList.addOnItemTouchListener(new OnItemTouchListener() { | ||||
|     private void initAdapter() { | ||||
|         adapter = new ContributionsListAdapter(this, mediaClient); | ||||
|     } | ||||
| 
 | ||||
|       /** | ||||
|        * Silently observe and/or take over touch events sent to the RecyclerView before | ||||
|        * they are handled by either the RecyclerView itself or its child views. | ||||
|        */ | ||||
|       @Override | ||||
|       public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) { | ||||
|         if (e.getAction() == MotionEvent.ACTION_DOWN) { | ||||
|           if (isFabOpen) { | ||||
|             animateFAB(isFabOpen); | ||||
|           } | ||||
|     @Override | ||||
|     public void onViewCreated(final View view, @Nullable final Bundle savedInstanceState) { | ||||
|         super.onViewCreated(view, savedInstanceState); | ||||
|         initRecyclerView(); | ||||
|         initializeAnimations(); | ||||
|         setListeners(); | ||||
|     } | ||||
| 
 | ||||
|     private void initRecyclerView() { | ||||
|         final GridLayoutManager layoutManager = new GridLayoutManager(getContext(), | ||||
|             getSpanCount(getResources().getConfiguration().orientation)); | ||||
|         rvContributionsList.setLayoutManager(layoutManager); | ||||
| 
 | ||||
|         //Setting flicker animation of recycler view to false. | ||||
|         final ItemAnimator animator = rvContributionsList.getItemAnimator(); | ||||
|         if (animator instanceof SimpleItemAnimator) { | ||||
|             ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false); | ||||
|         } | ||||
|         return false; | ||||
|       } | ||||
| 
 | ||||
|       /** | ||||
|        * Process a touch event as part of a gesture that was claimed by returning true | ||||
|        * from a previous call to {@link #onInterceptTouchEvent}. | ||||
|        * | ||||
|        * @param rv | ||||
|        * @param e  MotionEvent describing the touch event. All coordinates are in the | ||||
|        *           RecyclerView's coordinate system. | ||||
|        */ | ||||
|       @Override | ||||
|       public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) { | ||||
|         //required abstract method DO NOT DELETE | ||||
|       } | ||||
| 
 | ||||
|       /** | ||||
|        * Called when a child of RecyclerView does not want RecyclerView and its ancestors | ||||
|        * to intercept touch events with {@link ViewGroup#onInterceptTouchEvent(MotionEvent)}. | ||||
|        * | ||||
|        * @param disallowIntercept True if the child does not want the parent to intercept | ||||
|        *                          touch events. | ||||
|        */ | ||||
|       @Override | ||||
|       public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { | ||||
|         //required abstract method DO NOT DELETE | ||||
|       } | ||||
| 
 | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   private int getSpanCount(final int orientation) { | ||||
|     return orientation == Configuration.ORIENTATION_LANDSCAPE ? | ||||
|         SPAN_COUNT_LANDSCAPE : SPAN_COUNT_PORTRAIT; | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void onConfigurationChanged(final Configuration newConfig) { | ||||
|     super.onConfigurationChanged(newConfig); | ||||
|     // check orientation | ||||
|     fab_layout.setOrientation(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ? | ||||
|         LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); | ||||
|     rvContributionsList | ||||
|         .setLayoutManager(new GridLayoutManager(getContext(), getSpanCount(newConfig.orientation))); | ||||
|   } | ||||
| 
 | ||||
|   private void initializeAnimations() { | ||||
|     fab_open = AnimationUtils.loadAnimation(getActivity(), R.anim.fab_open); | ||||
|     fab_close = AnimationUtils.loadAnimation(getActivity(), R.anim.fab_close); | ||||
|     rotate_forward = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate_forward); | ||||
|     rotate_backward = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate_backward); | ||||
|   } | ||||
| 
 | ||||
|   private void setListeners() { | ||||
|     fabPlus.setOnClickListener(view -> animateFAB(isFabOpen)); | ||||
|     fabCamera.setOnClickListener(view -> { | ||||
|       controller.initiateCameraPick(getActivity()); | ||||
|       animateFAB(isFabOpen); | ||||
|     }); | ||||
|     fabGallery.setOnClickListener(view -> { | ||||
|       controller.initiateGalleryPick(getActivity(), true); | ||||
|       animateFAB(isFabOpen); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   private void animateFAB(final boolean isFabOpen) { | ||||
|     this.isFabOpen = !isFabOpen; | ||||
|     if (fabPlus.isShown()) { | ||||
|       if (isFabOpen) { | ||||
|         fabPlus.startAnimation(rotate_backward); | ||||
|         fabCamera.startAnimation(fab_close); | ||||
|         fabGallery.startAnimation(fab_close); | ||||
|         fabCamera.hide(); | ||||
|         fabGallery.hide(); | ||||
|       } else { | ||||
|         fabPlus.startAnimation(rotate_forward); | ||||
|         fabCamera.startAnimation(fab_open); | ||||
|         fabGallery.startAnimation(fab_open); | ||||
|         fabCamera.show(); | ||||
|         fabGallery.show(); | ||||
|       } | ||||
|       this.isFabOpen = !isFabOpen; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Shows welcome message if user has no contributions yet i.e. new user. | ||||
|    */ | ||||
|   @Override | ||||
|   public void showWelcomeTip(final boolean shouldShow) { | ||||
|     noContributionsYet.setVisibility(shouldShow ? VISIBLE : GONE); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Responsible to set progress bar invisible and visible | ||||
|    * | ||||
|    * @param shouldShow True when contributions list should be hidden. | ||||
|    */ | ||||
|   @Override | ||||
|   public void showProgress(final boolean shouldShow) { | ||||
|     progressBar.setVisibility(shouldShow ? VISIBLE : GONE); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void showNoContributionsUI(final boolean shouldShow) { | ||||
|     noContributionsYet.setVisibility(shouldShow ? VISIBLE : GONE); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void onSaveInstanceState(@NonNull Bundle outState) { | ||||
|     super.onSaveInstanceState(outState); | ||||
|     final GridLayoutManager layoutManager = (GridLayoutManager) rvContributionsList | ||||
|         .getLayoutManager(); | ||||
|     outState.putParcelable(RV_STATE, layoutManager.onSaveInstanceState()); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void onViewStateRestored(@Nullable Bundle savedInstanceState) { | ||||
|     super.onViewStateRestored(savedInstanceState); | ||||
|     if (null != savedInstanceState) { | ||||
|       final Parcelable savedRecyclerLayoutState = savedInstanceState.getParcelable(RV_STATE); | ||||
|       rvContributionsList.getLayoutManager().onRestoreInstanceState(savedRecyclerLayoutState); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void retryUpload(final Contribution contribution) { | ||||
|     if (null != callback) {//Just being safe, ideally they won't be called when detached | ||||
|       callback.retryUpload(contribution); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void deleteUpload(final Contribution contribution) { | ||||
|     contributionsListPresenter.deleteUpload(contribution); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void openMediaDetail(final int position, boolean isWikipediaButtonDisplayed) { | ||||
|     if (null != callback) {//Just being safe, ideally they won't be called when detached | ||||
|       callback.showDetail(position, isWikipediaButtonDisplayed); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Handle callback for wikipedia icon clicked | ||||
|    * | ||||
|    * @param contribution | ||||
|    */ | ||||
|   @Override | ||||
|   public void addImageToWikipedia(Contribution contribution) { | ||||
|     DialogUtil.showAlertDialog(getActivity(), | ||||
|         getString(R.string.add_picture_to_wikipedia_article_title), | ||||
|         String.format(getString(R.string.add_picture_to_wikipedia_article_desc), | ||||
|             Locale.getDefault().getDisplayLanguage()), | ||||
|         () -> { | ||||
|           showAddImageToWikipediaInstructions(contribution); | ||||
|         }, () -> { | ||||
|           // do nothing | ||||
|         contributionsListPresenter.setup(); | ||||
|         contributionsListPresenter.contributionList.observe(this.getViewLifecycleOwner(), list -> { | ||||
|             contributionsSize = list.size(); | ||||
|             adapter.submitList(list); | ||||
|             callback.notifyDataSetChanged(); | ||||
|         }); | ||||
|   } | ||||
|         rvContributionsList.setAdapter(adapter); | ||||
|         adapter.registerAdapterDataObserver(new AdapterDataObserver() { | ||||
|             @Override | ||||
|             public void onItemRangeInserted(int positionStart, int itemCount) { | ||||
|                 super.onItemRangeInserted(positionStart, itemCount); | ||||
|                 if (itemCount > 0 && positionStart == 0) { | ||||
|                     if (adapter.getContributionForPosition(positionStart) != null) { | ||||
|                         rvContributionsList | ||||
|                             .scrollToPosition(0);//Newly upload items are always added to the top | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|   /** | ||||
|    * Pauses the current upload | ||||
|    * @param contribution | ||||
|    */ | ||||
|   @Override | ||||
|   public void pauseUpload(Contribution contribution) { | ||||
|     ViewUtil.showShortToast(getContext(), R.string.pausing_upload); | ||||
|     callback.pauseUpload(contribution); | ||||
|   } | ||||
|             /** | ||||
|              * Called whenever items in the list have changed | ||||
|              * Calls viewPagerNotifyDataSetChanged() that will notify the viewpager | ||||
|              */ | ||||
|             @Override | ||||
|             public void onItemRangeChanged(final int positionStart, final int itemCount) { | ||||
|                 super.onItemRangeChanged(positionStart, itemCount); | ||||
|                 callback.viewPagerNotifyDataSetChanged(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|   /** | ||||
|    * Resumes the current upload | ||||
|    * @param contribution | ||||
|    */ | ||||
|   @Override | ||||
|   public void resumeUpload(Contribution contribution) { | ||||
|     ViewUtil.showShortToast(getContext(), R.string.resuming_upload); | ||||
|     callback.retryUpload(contribution); | ||||
|   } | ||||
|         //Fab close on touch outside (Scrolling or taping on item triggers this action). | ||||
|         rvContributionsList.addOnItemTouchListener(new OnItemTouchListener() { | ||||
| 
 | ||||
|   /** | ||||
|    * Display confirmation dialog with instructions when the user tries to add image to wikipedia | ||||
|    * | ||||
|    * @param contribution | ||||
|    */ | ||||
|   private void showAddImageToWikipediaInstructions(Contribution contribution) { | ||||
|     FragmentManager fragmentManager = getFragmentManager(); | ||||
|     WikipediaInstructionsDialogFragment fragment = WikipediaInstructionsDialogFragment | ||||
|         .newInstance(contribution); | ||||
|     fragment.setCallback(this::onConfirmClicked); | ||||
|     fragment.show(fragmentManager, "WikimediaFragment"); | ||||
|   } | ||||
|             /** | ||||
|              * Silently observe and/or take over touch events sent to the RecyclerView before | ||||
|              * they are handled by either the RecyclerView itself or its child views. | ||||
|              */ | ||||
|             @Override | ||||
|             public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) { | ||||
|                 if (e.getAction() == MotionEvent.ACTION_DOWN) { | ||||
|                     if (isFabOpen) { | ||||
|                         animateFAB(isFabOpen); | ||||
|                     } | ||||
|                 } | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             /** | ||||
|              * Process a touch event as part of a gesture that was claimed by returning true | ||||
|              * from a previous call to {@link #onInterceptTouchEvent}. | ||||
|              * | ||||
|              * @param rv | ||||
|              * @param e  MotionEvent describing the touch event. All coordinates are in the | ||||
|              *           RecyclerView's coordinate system. | ||||
|              */ | ||||
|             @Override | ||||
|             public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) { | ||||
|                 //required abstract method DO NOT DELETE | ||||
|             } | ||||
| 
 | ||||
|   public Media getMediaAtPosition(final int i) { | ||||
|     if(adapter.getContributionForPosition(i) != null) { | ||||
|       return adapter.getContributionForPosition(i).getMedia(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
|             /** | ||||
|              * Called when a child of RecyclerView does not want RecyclerView and its ancestors | ||||
|              * to intercept touch events with {@link ViewGroup#onInterceptTouchEvent(MotionEvent)}. | ||||
|              * | ||||
|              * @param disallowIntercept True if the child does not want the parent to intercept | ||||
|              *                          touch events. | ||||
|              */ | ||||
|             @Override | ||||
|             public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { | ||||
|                 //required abstract method DO NOT DELETE | ||||
|             } | ||||
| 
 | ||||
|   public int getTotalMediaCount() { | ||||
|     return contributionsSize; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Open the editor for the language Wikipedia | ||||
|    * | ||||
|    * @param contribution | ||||
|    */ | ||||
|   @Override | ||||
|   public void onConfirmClicked(@Nullable Contribution contribution, boolean copyWikicode) { | ||||
|     if (copyWikicode) { | ||||
|       String wikicode = contribution.getMedia().getWikiCode(); | ||||
|       Utils.copy("wikicode", wikicode, getContext()); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     final String url = | ||||
|         languageWikipediaSite.mobileUrl() + "/wiki/" + contribution.getWikidataPlace() | ||||
|             .getWikipediaPageTitle(); | ||||
|     Utils.handleWebUrl(getContext(), Uri.parse(url)); | ||||
|   } | ||||
|     private int getSpanCount(final int orientation) { | ||||
|         return orientation == Configuration.ORIENTATION_LANDSCAPE ? | ||||
|             SPAN_COUNT_LANDSCAPE : SPAN_COUNT_PORTRAIT; | ||||
|     } | ||||
| 
 | ||||
|   public Integer getContributionStateAt(int position) { | ||||
|     return adapter.getContributionForPosition(position).getState(); | ||||
|   } | ||||
|     @Override | ||||
|     public void onConfigurationChanged(final Configuration newConfig) { | ||||
|         super.onConfigurationChanged(newConfig); | ||||
|         // check orientation | ||||
|         fab_layout.setOrientation(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ? | ||||
|             LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); | ||||
|         rvContributionsList | ||||
|             .setLayoutManager( | ||||
|                 new GridLayoutManager(getContext(), getSpanCount(newConfig.orientation))); | ||||
|     } | ||||
| 
 | ||||
|   public interface Callback { | ||||
|     private void initializeAnimations() { | ||||
|         fab_open = AnimationUtils.loadAnimation(getActivity(), R.anim.fab_open); | ||||
|         fab_close = AnimationUtils.loadAnimation(getActivity(), R.anim.fab_close); | ||||
|         rotate_forward = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate_forward); | ||||
|         rotate_backward = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate_backward); | ||||
|     } | ||||
| 
 | ||||
|     void notifyDataSetChanged(); | ||||
|     private void setListeners() { | ||||
|         fabPlus.setOnClickListener(view -> animateFAB(isFabOpen)); | ||||
|         fabCamera.setOnClickListener(view -> { | ||||
|             controller.initiateCameraPick(getActivity()); | ||||
|             animateFAB(isFabOpen); | ||||
|         }); | ||||
|         fabGallery.setOnClickListener(view -> { | ||||
|             controller.initiateGalleryPick(getActivity(), true); | ||||
|             animateFAB(isFabOpen); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     void retryUpload(Contribution contribution); | ||||
|     private void animateFAB(final boolean isFabOpen) { | ||||
|         this.isFabOpen = !isFabOpen; | ||||
|         if (fabPlus.isShown()) { | ||||
|             if (isFabOpen) { | ||||
|                 fabPlus.startAnimation(rotate_backward); | ||||
|                 fabCamera.startAnimation(fab_close); | ||||
|                 fabGallery.startAnimation(fab_close); | ||||
|                 fabCamera.hide(); | ||||
|                 fabGallery.hide(); | ||||
|             } else { | ||||
|                 fabPlus.startAnimation(rotate_forward); | ||||
|                 fabCamera.startAnimation(fab_open); | ||||
|                 fabGallery.startAnimation(fab_open); | ||||
|                 fabCamera.show(); | ||||
|                 fabGallery.show(); | ||||
|             } | ||||
|             this.isFabOpen = !isFabOpen; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void showDetail(int position, boolean isWikipediaButtonDisplayed); | ||||
|     /** | ||||
|      * Shows welcome message if user has no contributions yet i.e. new user. | ||||
|      */ | ||||
|     @Override | ||||
|     public void showWelcomeTip(final boolean shouldShow) { | ||||
|         noContributionsYet.setVisibility(shouldShow ? VISIBLE : GONE); | ||||
|     } | ||||
| 
 | ||||
|     void pauseUpload(Contribution contribution); | ||||
|     /** | ||||
|      * Responsible to set progress bar invisible and visible | ||||
|      * | ||||
|      * @param shouldShow True when contributions list should be hidden. | ||||
|      */ | ||||
|     @Override | ||||
|     public void showProgress(final boolean shouldShow) { | ||||
|         progressBar.setVisibility(shouldShow ? VISIBLE : GONE); | ||||
|     } | ||||
| 
 | ||||
|     // Notify the viewpager that number of items have changed. | ||||
|     void viewPagerNotifyDataSetChanged(); | ||||
|   } | ||||
|     @Override | ||||
|     public void showNoContributionsUI(final boolean shouldShow) { | ||||
|         noContributionsYet.setVisibility(shouldShow ? VISIBLE : GONE); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onSaveInstanceState(@NonNull Bundle outState) { | ||||
|         super.onSaveInstanceState(outState); | ||||
|         final GridLayoutManager layoutManager = (GridLayoutManager) rvContributionsList | ||||
|             .getLayoutManager(); | ||||
|         outState.putParcelable(RV_STATE, layoutManager.onSaveInstanceState()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onViewStateRestored(@Nullable Bundle savedInstanceState) { | ||||
|         super.onViewStateRestored(savedInstanceState); | ||||
|         if (null != savedInstanceState) { | ||||
|             final Parcelable savedRecyclerLayoutState = savedInstanceState.getParcelable(RV_STATE); | ||||
|             rvContributionsList.getLayoutManager().onRestoreInstanceState(savedRecyclerLayoutState); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void retryUpload(final Contribution contribution) { | ||||
|         if (null != callback) {//Just being safe, ideally they won't be called when detached | ||||
|             callback.retryUpload(contribution); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void deleteUpload(final Contribution contribution) { | ||||
|         contributionsListPresenter.deleteUpload(contribution); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void openMediaDetail(final int position, boolean isWikipediaButtonDisplayed) { | ||||
|         if (null != callback) {//Just being safe, ideally they won't be called when detached | ||||
|             callback.showDetail(position, isWikipediaButtonDisplayed); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Handle callback for wikipedia icon clicked | ||||
|      * | ||||
|      * @param contribution | ||||
|      */ | ||||
|     @Override | ||||
|     public void addImageToWikipedia(Contribution contribution) { | ||||
|         DialogUtil.showAlertDialog(getActivity(), | ||||
|             getString(R.string.add_picture_to_wikipedia_article_title), | ||||
|             String.format(getString(R.string.add_picture_to_wikipedia_article_desc), | ||||
|                 Locale.getDefault().getDisplayLanguage()), | ||||
|             () -> { | ||||
|                 showAddImageToWikipediaInstructions(contribution); | ||||
|             }, () -> { | ||||
|                 // do nothing | ||||
|             }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Pauses the current upload | ||||
|      * | ||||
|      * @param contribution | ||||
|      */ | ||||
|     @Override | ||||
|     public void pauseUpload(Contribution contribution) { | ||||
|         ViewUtil.showShortToast(getContext(), R.string.pausing_upload); | ||||
|         callback.pauseUpload(contribution); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Resumes the current upload | ||||
|      * | ||||
|      * @param contribution | ||||
|      */ | ||||
|     @Override | ||||
|     public void resumeUpload(Contribution contribution) { | ||||
|         ViewUtil.showShortToast(getContext(), R.string.resuming_upload); | ||||
|         callback.retryUpload(contribution); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Display confirmation dialog with instructions when the user tries to add image to wikipedia | ||||
|      * | ||||
|      * @param contribution | ||||
|      */ | ||||
|     private void showAddImageToWikipediaInstructions(Contribution contribution) { | ||||
|         FragmentManager fragmentManager = getFragmentManager(); | ||||
|         WikipediaInstructionsDialogFragment fragment = WikipediaInstructionsDialogFragment | ||||
|             .newInstance(contribution); | ||||
|         fragment.setCallback(this::onConfirmClicked); | ||||
|         fragment.show(fragmentManager, "WikimediaFragment"); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public Media getMediaAtPosition(final int i) { | ||||
|         if (adapter.getContributionForPosition(i) != null) { | ||||
|             return adapter.getContributionForPosition(i).getMedia(); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     public int getTotalMediaCount() { | ||||
|         return contributionsSize; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Open the editor for the language Wikipedia | ||||
|      * | ||||
|      * @param contribution | ||||
|      */ | ||||
|     @Override | ||||
|     public void onConfirmClicked(@Nullable Contribution contribution, boolean copyWikicode) { | ||||
|         if (copyWikicode) { | ||||
|             String wikicode = contribution.getMedia().getWikiCode(); | ||||
|             Utils.copy("wikicode", wikicode, getContext()); | ||||
|         } | ||||
| 
 | ||||
|         final String url = | ||||
|             languageWikipediaSite.mobileUrl() + "/wiki/" + contribution.getWikidataPlace() | ||||
|                 .getWikipediaPageTitle(); | ||||
|         Utils.handleWebUrl(getContext(), Uri.parse(url)); | ||||
|     } | ||||
| 
 | ||||
|     public Integer getContributionStateAt(int position) { | ||||
|         return adapter.getContributionForPosition(position).getState(); | ||||
|     } | ||||
| 
 | ||||
|     public interface Callback { | ||||
| 
 | ||||
|         void notifyDataSetChanged(); | ||||
| 
 | ||||
|         void retryUpload(Contribution contribution); | ||||
| 
 | ||||
|         void showDetail(int position, boolean isWikipediaButtonDisplayed); | ||||
| 
 | ||||
|         void pauseUpload(Contribution contribution); | ||||
| 
 | ||||
|         // Notify the viewpager that number of items have changed. | ||||
|         void viewPagerNotifyDataSetChanged(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -15,57 +15,58 @@ import javax.inject.Named; | |||
|  */ | ||||
| public class ContributionsListPresenter implements UserActionListener { | ||||
| 
 | ||||
|   private final ContributionBoundaryCallback contributionBoundaryCallback; | ||||
|   private final ContributionsRepository repository; | ||||
|   private final Scheduler ioThreadScheduler; | ||||
|     private final ContributionBoundaryCallback contributionBoundaryCallback; | ||||
|     private final ContributionsRepository repository; | ||||
|     private final Scheduler ioThreadScheduler; | ||||
| 
 | ||||
|   private final CompositeDisposable compositeDisposable; | ||||
|     private final CompositeDisposable compositeDisposable; | ||||
| 
 | ||||
|   LiveData<PagedList<Contribution>> contributionList; | ||||
|     LiveData<PagedList<Contribution>> contributionList; | ||||
| 
 | ||||
|   @Inject | ||||
|   ContributionsListPresenter( | ||||
|       final ContributionBoundaryCallback contributionBoundaryCallback, | ||||
|       final ContributionsRepository repository, | ||||
|       @Named(CommonsApplicationModule.IO_THREAD) final Scheduler ioThreadScheduler) { | ||||
|     this.contributionBoundaryCallback = contributionBoundaryCallback; | ||||
|     this.repository = repository; | ||||
|     this.ioThreadScheduler = ioThreadScheduler; | ||||
|     compositeDisposable = new CompositeDisposable(); | ||||
|   } | ||||
|     @Inject | ||||
|     ContributionsListPresenter( | ||||
|         final ContributionBoundaryCallback contributionBoundaryCallback, | ||||
|         final ContributionsRepository repository, | ||||
|         @Named(CommonsApplicationModule.IO_THREAD) final Scheduler ioThreadScheduler) { | ||||
|         this.contributionBoundaryCallback = contributionBoundaryCallback; | ||||
|         this.repository = repository; | ||||
|         this.ioThreadScheduler = ioThreadScheduler; | ||||
|         compositeDisposable = new CompositeDisposable(); | ||||
|     } | ||||
| 
 | ||||
|   @Override | ||||
|   public void onAttachView(final ContributionsListContract.View view) { | ||||
|   } | ||||
|     @Override | ||||
|     public void onAttachView(final ContributionsListContract.View view) { | ||||
|     } | ||||
| 
 | ||||
|   /** | ||||
|    * Setup the paged list. This method sets the configuration for paged list and ties it up with the | ||||
|    * live data object. This method can be tweaked to update the lazy loading behavior of the | ||||
|    * contributions list | ||||
|    */ | ||||
|   void setup() { | ||||
|     final PagedList.Config pagedListConfig = | ||||
|         (new PagedList.Config.Builder()) | ||||
|             .setPrefetchDistance(50) | ||||
|             .setPageSize(10).build(); | ||||
|     contributionList = (new LivePagedListBuilder(repository.fetchContributions(), pagedListConfig) | ||||
|         .setBoundaryCallback(contributionBoundaryCallback)).build(); | ||||
|   } | ||||
|     /** | ||||
|      * Setup the paged list. This method sets the configuration for paged list and ties it up with | ||||
|      * the live data object. This method can be tweaked to update the lazy loading behavior of the | ||||
|      * contributions list | ||||
|      */ | ||||
|     void setup() { | ||||
|         final PagedList.Config pagedListConfig = | ||||
|             (new PagedList.Config.Builder()) | ||||
|                 .setPrefetchDistance(50) | ||||
|                 .setPageSize(10).build(); | ||||
|         contributionList = (new LivePagedListBuilder(repository.fetchContributions(), | ||||
|             pagedListConfig) | ||||
|             .setBoundaryCallback(contributionBoundaryCallback)).build(); | ||||
|     } | ||||
| 
 | ||||
|   @Override | ||||
|   public void onDetachView() { | ||||
|     compositeDisposable.clear(); | ||||
|   } | ||||
|     @Override | ||||
|     public void onDetachView() { | ||||
|         compositeDisposable.clear(); | ||||
|     } | ||||
| 
 | ||||
|   /** | ||||
|    * Delete a failed contribution from the local db | ||||
|    */ | ||||
|   @Override | ||||
|   public void deleteUpload(final Contribution contribution) { | ||||
|     compositeDisposable.add(repository | ||||
|         .deleteContributionFromDB(contribution) | ||||
|         .subscribeOn(ioThreadScheduler) | ||||
|         .subscribe()); | ||||
|   } | ||||
|     /** | ||||
|      * Delete a failed contribution from the local db | ||||
|      */ | ||||
|     @Override | ||||
|     public void deleteUpload(final Contribution contribution) { | ||||
|         compositeDisposable.add(repository | ||||
|             .deleteContributionFromDB(contribution) | ||||
|             .subscribeOn(ioThreadScheduler) | ||||
|             .subscribe()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jamie Brown
						Jamie Brown