mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-31 06:43:56 +01:00 
			
		
		
		
	Merge branch 'main' into new-branch-local
This commit is contained in:
		
						commit
						f09e31934d
					
				
					 6 changed files with 160 additions and 108 deletions
				
			
		|  | @ -2,7 +2,6 @@ package fr.free.nrw.commons.contributions | ||||||
| 
 | 
 | ||||||
| import androidx.paging.PagedList.BoundaryCallback | import androidx.paging.PagedList.BoundaryCallback | ||||||
| import fr.free.nrw.commons.auth.SessionManager | import fr.free.nrw.commons.auth.SessionManager | ||||||
| import fr.free.nrw.commons.di.CommonsApplicationModule |  | ||||||
| import fr.free.nrw.commons.di.CommonsApplicationModule.Companion.IO_THREAD | import fr.free.nrw.commons.di.CommonsApplicationModule.Companion.IO_THREAD | ||||||
| import fr.free.nrw.commons.media.MediaClient | import fr.free.nrw.commons.media.MediaClient | ||||||
| import io.reactivex.Scheduler | import io.reactivex.Scheduler | ||||||
|  | @ -31,10 +30,7 @@ class ContributionBoundaryCallback | ||||||
|          * network |          * network | ||||||
|          */ |          */ | ||||||
|         override fun onZeroItemsLoaded() { |         override fun onZeroItemsLoaded() { | ||||||
|             if (sessionManager.userName != null) { |             refreshList() | ||||||
|                 mediaClient.resetUserNameContinuation(sessionManager.userName!!) |  | ||||||
|             } |  | ||||||
|             fetchContributions() |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /** |         /** | ||||||
|  | @ -52,9 +48,25 @@ class ContributionBoundaryCallback | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /** |         /** | ||||||
|          * Fetches contributions using the MediaWiki API |          * Fetch list from network and save it to local DB. | ||||||
|  |          * | ||||||
|  |          * @param onRefreshFinish callback to invoke when operations finishes | ||||||
|  |          * with either error or success. | ||||||
|          */ |          */ | ||||||
|         private fun fetchContributions() { |         fun refreshList(onRefreshFinish: () -> Unit = {}){ | ||||||
|  |             if (sessionManager.userName != null) { | ||||||
|  |                 mediaClient.resetUserNameContinuation(sessionManager.userName!!) | ||||||
|  |             } | ||||||
|  |             fetchContributions(onRefreshFinish) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /** | ||||||
|  |          * Fetches contributions using the MediaWiki API | ||||||
|  |          * | ||||||
|  |          *   @param onRefreshFinish callback to invoke when operations finishes | ||||||
|  |          *   with either error or success. | ||||||
|  |          */ | ||||||
|  |         private fun fetchContributions(onRefreshFinish: () -> Unit = {}) { | ||||||
|             if (sessionManager.userName != null) { |             if (sessionManager.userName != null) { | ||||||
|                 userName |                 userName | ||||||
|                     ?.let { userName -> |                     ?.let { userName -> | ||||||
|  | @ -65,12 +77,15 @@ class ContributionBoundaryCallback | ||||||
|                                     Contribution(media = media, state = Contribution.STATE_COMPLETED) |                                     Contribution(media = media, state = Contribution.STATE_COMPLETED) | ||||||
|                                 } |                                 } | ||||||
|                             }.subscribeOn(ioThreadScheduler) |                             }.subscribeOn(ioThreadScheduler) | ||||||
|                             .subscribe(::saveContributionsToDB) { error: Throwable -> |                             .subscribe({ list -> | ||||||
|  |                                 saveContributionsToDB(list, onRefreshFinish) | ||||||
|  |                             },{ error -> | ||||||
|  |                                 onRefreshFinish() | ||||||
|                                 Timber.e( |                                 Timber.e( | ||||||
|                                     "Failed to fetch contributions: %s", |                                     "Failed to fetch contributions: %s", | ||||||
|                                     error.message, |                                     error.message, | ||||||
|                                 ) |                                 ) | ||||||
|                             } |                             }) | ||||||
|                     }?.let { |                     }?.let { | ||||||
|                         compositeDisposable.add( |                         compositeDisposable.add( | ||||||
|                             it, |                             it, | ||||||
|  | @ -83,13 +98,16 @@ class ContributionBoundaryCallback | ||||||
| 
 | 
 | ||||||
|         /** |         /** | ||||||
|          * Saves the contributions the the local DB |          * Saves the contributions the the local DB | ||||||
|  |          * | ||||||
|  |          * @param onRefreshFinish callback to invoke when successfully saved to DB. | ||||||
|          */ |          */ | ||||||
|         private fun saveContributionsToDB(contributions: List<Contribution>) { |         private fun saveContributionsToDB(contributions: List<Contribution>, onRefreshFinish: () -> Unit) { | ||||||
|             compositeDisposable.add( |             compositeDisposable.add( | ||||||
|                 repository |                 repository | ||||||
|                     .save(contributions) |                     .save(contributions) | ||||||
|                     .subscribeOn(ioThreadScheduler) |                     .subscribeOn(ioThreadScheduler) | ||||||
|                     .subscribe { longs: List<Long?>? -> |                     .subscribe { longs: List<Long?>? -> | ||||||
|  |                         onRefreshFinish() | ||||||
|                         repository["last_fetch_timestamp"] = System.currentTimeMillis() |                         repository["last_fetch_timestamp"] = System.currentTimeMillis() | ||||||
|                     }, |                     }, | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| package fr.free.nrw.commons.contributions; | package fr.free.nrw.commons.contributions; | ||||||
| 
 | 
 | ||||||
|  | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; | ||||||
| import fr.free.nrw.commons.BasePresenter; | import fr.free.nrw.commons.BasePresenter; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -17,5 +18,8 @@ public class ContributionsListContract { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public interface UserActionListener extends BasePresenter<View> { |     public interface UserActionListener extends BasePresenter<View> { | ||||||
|  | 
 | ||||||
|  |         void refreshList(SwipeRefreshLayout swipeRefreshLayout); | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -191,6 +191,15 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl | ||||||
| 
 | 
 | ||||||
|         initAdapter(); |         initAdapter(); | ||||||
| 
 | 
 | ||||||
|  |         // pull down to refresh only enabled for self user. | ||||||
|  |         if(Objects.equals(sessionManager.getUserName(), userName)){ | ||||||
|  |             binding.swipeRefreshLayout.setOnRefreshListener(() -> { | ||||||
|  |                 contributionsListPresenter.refreshList(binding.swipeRefreshLayout); | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             binding.swipeRefreshLayout.setEnabled(false); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         return binding.getRoot(); |         return binding.getRoot(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,14 +8,15 @@ import androidx.paging.DataSource; | ||||||
| import androidx.paging.DataSource.Factory; | import androidx.paging.DataSource.Factory; | ||||||
| import androidx.paging.LivePagedListBuilder; | import androidx.paging.LivePagedListBuilder; | ||||||
| import androidx.paging.PagedList; | import androidx.paging.PagedList; | ||||||
|  | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; | ||||||
| import fr.free.nrw.commons.contributions.ContributionsListContract.UserActionListener; | import fr.free.nrw.commons.contributions.ContributionsListContract.UserActionListener; | ||||||
| import fr.free.nrw.commons.di.CommonsApplicationModule; |  | ||||||
| import io.reactivex.Scheduler; | import io.reactivex.Scheduler; | ||||||
| import io.reactivex.disposables.CompositeDisposable; | import io.reactivex.disposables.CompositeDisposable; | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import javax.inject.Inject; | import javax.inject.Inject; | ||||||
| import javax.inject.Named; | import javax.inject.Named; | ||||||
|  | import kotlin.Unit; | ||||||
|  | import kotlin.jvm.functions.Function0; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * The presenter class for Contributions |  * The presenter class for Contributions | ||||||
|  | @ -95,4 +96,17 @@ public class ContributionsListPresenter implements UserActionListener { | ||||||
|         contributionBoundaryCallback.dispose(); |         contributionBoundaryCallback.dispose(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * It is used to refresh list. | ||||||
|  |      * | ||||||
|  |      * @param swipeRefreshLayout used to stop refresh animation when | ||||||
|  |      * refresh finishes. | ||||||
|  |      */ | ||||||
|  |     @Override | ||||||
|  |     public void refreshList(final SwipeRefreshLayout swipeRefreshLayout) { | ||||||
|  |         contributionBoundaryCallback.refreshList(() -> { | ||||||
|  |             swipeRefreshLayout.setRefreshing(false); | ||||||
|  |             return Unit.INSTANCE; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,32 +1,36 @@ | ||||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | 
 | ||||||
|  | <androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|   xmlns:app="http://schemas.android.com/apk/res-auto" |   xmlns:app="http://schemas.android.com/apk/res-auto" | ||||||
|   xmlns:tools="http://schemas.android.com/tools" |   xmlns:tools="http://schemas.android.com/tools" | ||||||
|     android:orientation="vertical" |   android:id="@+id/swipe_refresh_layout" | ||||||
|  |   android:layout_width="match_parent" | ||||||
|  |   android:layout_height="match_parent"> | ||||||
|  | 
 | ||||||
|  |   <RelativeLayout | ||||||
|     android:layout_width="match_parent" |     android:layout_width="match_parent" | ||||||
|     android:layout_height="match_parent" |     android:layout_height="match_parent" | ||||||
|     android:background="?attr/contributionsListBackground" |     android:background="?attr/contributionsListBackground" | ||||||
|     > |     android:orientation="vertical"> | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     <TextView |     <TextView | ||||||
|       android:id="@+id/noContributionsYet" |       android:id="@+id/noContributionsYet" | ||||||
|       android:layout_width="match_parent" |       android:layout_width="match_parent" | ||||||
|       android:layout_height="wrap_content" |       android:layout_height="wrap_content" | ||||||
|         android:text="@string/no_uploads" |  | ||||||
|         android:gravity="center" |  | ||||||
|       android:layout_centerInParent="true" |       android:layout_centerInParent="true" | ||||||
|         android:visibility="gone" |  | ||||||
|         android:layout_marginRight="@dimen/tiny_gap" |  | ||||||
|       android:layout_marginEnd="@dimen/tiny_gap" |       android:layout_marginEnd="@dimen/tiny_gap" | ||||||
|         /> |       android:layout_marginRight="@dimen/tiny_gap" | ||||||
|  |       android:gravity="center" | ||||||
|  |       android:text="@string/no_uploads" | ||||||
|  |       android:visibility="gone" /> | ||||||
| 
 | 
 | ||||||
|     <ProgressBar |     <ProgressBar | ||||||
|       android:id="@+id/loadingContributionsProgressBar" |       android:id="@+id/loadingContributionsProgressBar" | ||||||
|       android:layout_width="wrap_content" |       android:layout_width="wrap_content" | ||||||
|       android:layout_height="wrap_content" |       android:layout_height="wrap_content" | ||||||
|       android:layout_centerInParent="true" |       android:layout_centerInParent="true" | ||||||
|       android:visibility="gone" |       android:visibility="gone" /> | ||||||
|       /> |  | ||||||
| 
 | 
 | ||||||
|     <RelativeLayout |     <RelativeLayout | ||||||
|       android:layout_width="match_parent" |       android:layout_width="match_parent" | ||||||
|  | @ -36,36 +40,35 @@ | ||||||
|       <androidx.appcompat.widget.AppCompatTextView |       <androidx.appcompat.widget.AppCompatTextView | ||||||
|         android:id="@+id/tv_contributions_of_user" |         android:id="@+id/tv_contributions_of_user" | ||||||
|         style="@style/MediaDetailTextLabel" |         style="@style/MediaDetailTextLabel" | ||||||
|           tools:text="Contributions of user : Ashish" |  | ||||||
|         android:layout_width="match_parent" |         android:layout_width="match_parent" | ||||||
|         android:layout_height="wrap_content" |         android:layout_height="wrap_content" | ||||||
|         android:padding="10dp" |         android:padding="10dp" | ||||||
|           tools:visibility="visible" |         android:visibility="gone" | ||||||
|           android:visibility="gone" /> |         tools:text="Contributions of user : Ashish" | ||||||
|  |         tools:visibility="visible" /> | ||||||
| 
 | 
 | ||||||
|       <androidx.recyclerview.widget.RecyclerView |       <androidx.recyclerview.widget.RecyclerView | ||||||
|         android:id="@+id/contributionsList" |         android:id="@+id/contributionsList" | ||||||
|         android:layout_width="match_parent" |         android:layout_width="match_parent" | ||||||
|         android:layout_height="match_parent" |         android:layout_height="match_parent" | ||||||
|         android:layout_below="@id/tv_contributions_of_user" |         android:layout_below="@id/tv_contributions_of_user" | ||||||
|           android:scrollbars="vertical" |  | ||||||
|         android:fadeScrollbars="true" |         android:fadeScrollbars="true" | ||||||
|  |         android:scrollbarSize="@dimen/dimen_6" | ||||||
|         android:scrollbarThumbVertical="@color/primaryColor" |         android:scrollbarThumbVertical="@color/primaryColor" | ||||||
|           android:scrollbarSize="@dimen/dimen_6"/> |         android:scrollbars="vertical" /> | ||||||
|     </RelativeLayout> |     </RelativeLayout> | ||||||
| 
 | 
 | ||||||
|     <LinearLayout |     <LinearLayout | ||||||
|       android:id="@+id/fab_layout" |       android:id="@+id/fab_layout" | ||||||
|       android:layout_width="wrap_content" |       android:layout_width="wrap_content" | ||||||
|       android:layout_height="wrap_content" |       android:layout_height="wrap_content" | ||||||
|         android:layout_alignParentBottom="true" |  | ||||||
|       android:layout_alignParentEnd="true" |       android:layout_alignParentEnd="true" | ||||||
|       android:layout_alignParentRight="true" |       android:layout_alignParentRight="true" | ||||||
|  |       android:layout_alignParentBottom="true" | ||||||
|       android:layout_marginRight="@dimen/medium_height" |       android:layout_marginRight="@dimen/medium_height" | ||||||
|       android:layout_marginBottom="@dimen/activity_margin_horizontal" |       android:layout_marginBottom="@dimen/activity_margin_horizontal" | ||||||
|         android:orientation="vertical" |  | ||||||
|       android:gravity="center" |       android:gravity="center" | ||||||
|         > |       android:orientation="vertical"> | ||||||
| 
 | 
 | ||||||
|       <com.google.android.material.floatingactionbutton.FloatingActionButton |       <com.google.android.material.floatingactionbutton.FloatingActionButton | ||||||
|         android:id="@+id/fab_camera" |         android:id="@+id/fab_camera" | ||||||
|  | @ -121,5 +124,6 @@ | ||||||
| 
 | 
 | ||||||
|     </LinearLayout> |     </LinearLayout> | ||||||
| 
 | 
 | ||||||
| </RelativeLayout> |   </RelativeLayout> | ||||||
| 
 | 
 | ||||||
|  | </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ import org.mockito.Mockito.mock | ||||||
| import org.mockito.Mockito.verifyNoInteractions | import org.mockito.Mockito.verifyNoInteractions | ||||||
| import org.mockito.MockitoAnnotations | import org.mockito.MockitoAnnotations | ||||||
| import java.lang.reflect.Method | import java.lang.reflect.Method | ||||||
|  | import kotlin.reflect.jvm.internal.impl.builtins.functions.FunctionTypeKind | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * The unit test class for ContributionBoundaryCallbackTest |  * The unit test class for ContributionBoundaryCallbackTest | ||||||
|  | @ -99,9 +100,10 @@ class ContributionBoundaryCallbackTest { | ||||||
|         val method: Method = |         val method: Method = | ||||||
|             ContributionBoundaryCallback::class.java.getDeclaredMethod( |             ContributionBoundaryCallback::class.java.getDeclaredMethod( | ||||||
|                 "fetchContributions", |                 "fetchContributions", | ||||||
|  |                 Function0::class.java | ||||||
|             ) |             ) | ||||||
|         method.isAccessible = true |         method.isAccessible = true | ||||||
|         method.invoke(contributionBoundaryCallback) |         method.invoke(contributionBoundaryCallback, {}) | ||||||
|         verify(repository).save(anyList()) |         verify(repository).save(anyList()) | ||||||
|         verify(mediaClient).getMediaListForUser(anyString()) |         verify(mediaClient).getMediaListForUser(anyString()) | ||||||
|     } |     } | ||||||
|  | @ -113,9 +115,10 @@ class ContributionBoundaryCallbackTest { | ||||||
|         val method: Method = |         val method: Method = | ||||||
|             ContributionBoundaryCallback::class.java.getDeclaredMethod( |             ContributionBoundaryCallback::class.java.getDeclaredMethod( | ||||||
|                 "fetchContributions", |                 "fetchContributions", | ||||||
|  |                 Function0::class.java | ||||||
|             ) |             ) | ||||||
|         method.isAccessible = true |         method.isAccessible = true | ||||||
|         method.invoke(contributionBoundaryCallback) |         method.invoke(contributionBoundaryCallback, {}) | ||||||
|         verifyNoInteractions(repository) |         verifyNoInteractions(repository) | ||||||
|         verify(mediaClient).getMediaListForUser(anyString()) |         verify(mediaClient).getMediaListForUser(anyString()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Sonal Yadav
						Sonal Yadav