Skip to content

Commit 4c9637c

Browse files
Add pull down to refresh in Contributions screen (commons-app#6041)
* pull down to refresh Signed-off-by: parneet-guraya <gurayaparneet@gmail.com> * add kdoc Signed-off-by: parneet-guraya <gurayaparneet@gmail.com> * only enabled for self user Signed-off-by: parneet-guraya <gurayaparneet@gmail.com> * fix test Signed-off-by: parneet-guraya <gurayaparneet@gmail.com> --------- Signed-off-by: parneet-guraya <gurayaparneet@gmail.com>
1 parent a4b7479 commit 4c9637c

File tree

6 files changed

+163
-111
lines changed

6 files changed

+163
-111
lines changed

app/src/main/java/fr/free/nrw/commons/contributions/ContributionBoundaryCallback.kt

+27-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package fr.free.nrw.commons.contributions
22

33
import androidx.paging.PagedList.BoundaryCallback
44
import fr.free.nrw.commons.auth.SessionManager
5-
import fr.free.nrw.commons.di.CommonsApplicationModule
65
import fr.free.nrw.commons.di.CommonsApplicationModule.Companion.IO_THREAD
76
import fr.free.nrw.commons.media.MediaClient
87
import io.reactivex.Scheduler
@@ -31,10 +30,7 @@ class ContributionBoundaryCallback
3130
* network
3231
*/
3332
override fun onZeroItemsLoaded() {
34-
if (sessionManager.userName != null) {
35-
mediaClient.resetUserNameContinuation(sessionManager.userName!!)
36-
}
37-
fetchContributions()
33+
refreshList()
3834
}
3935

4036
/**
@@ -51,10 +47,26 @@ class ContributionBoundaryCallback
5147
fetchContributions()
5248
}
5349

50+
/**
51+
* Fetch list from network and save it to local DB.
52+
*
53+
* @param onRefreshFinish callback to invoke when operations finishes
54+
* with either error or success.
55+
*/
56+
fun refreshList(onRefreshFinish: () -> Unit = {}){
57+
if (sessionManager.userName != null) {
58+
mediaClient.resetUserNameContinuation(sessionManager.userName!!)
59+
}
60+
fetchContributions(onRefreshFinish)
61+
}
62+
5463
/**
5564
* Fetches contributions using the MediaWiki API
65+
*
66+
* @param onRefreshFinish callback to invoke when operations finishes
67+
* with either error or success.
5668
*/
57-
private fun fetchContributions() {
69+
private fun fetchContributions(onRefreshFinish: () -> Unit = {}) {
5870
if (sessionManager.userName != null) {
5971
userName
6072
?.let { userName ->
@@ -65,12 +77,15 @@ class ContributionBoundaryCallback
6577
Contribution(media = media, state = Contribution.STATE_COMPLETED)
6678
}
6779
}.subscribeOn(ioThreadScheduler)
68-
.subscribe(::saveContributionsToDB) { error: Throwable ->
80+
.subscribe({ list ->
81+
saveContributionsToDB(list, onRefreshFinish)
82+
},{ error ->
83+
onRefreshFinish()
6984
Timber.e(
7085
"Failed to fetch contributions: %s",
7186
error.message,
7287
)
73-
}
88+
})
7489
}?.let {
7590
compositeDisposable.add(
7691
it,
@@ -83,13 +98,16 @@ class ContributionBoundaryCallback
8398

8499
/**
85100
* Saves the contributions the the local DB
101+
*
102+
* @param onRefreshFinish callback to invoke when successfully saved to DB.
86103
*/
87-
private fun saveContributionsToDB(contributions: List<Contribution>) {
104+
private fun saveContributionsToDB(contributions: List<Contribution>, onRefreshFinish: () -> Unit) {
88105
compositeDisposable.add(
89106
repository
90107
.save(contributions)
91108
.subscribeOn(ioThreadScheduler)
92109
.subscribe { longs: List<Long?>? ->
110+
onRefreshFinish()
93111
repository["last_fetch_timestamp"] = System.currentTimeMillis()
94112
},
95113
)

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListContract.java

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package fr.free.nrw.commons.contributions;
22

3+
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
34
import fr.free.nrw.commons.BasePresenter;
45

56
/**
@@ -17,5 +18,8 @@ public interface View {
1718
}
1819

1920
public interface UserActionListener extends BasePresenter<View> {
21+
22+
void refreshList(SwipeRefreshLayout swipeRefreshLayout);
23+
2024
}
2125
}

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java

+9
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,15 @@ public View onCreateView(
191191

192192
initAdapter();
193193

194+
// pull down to refresh only enabled for self user.
195+
if(Objects.equals(sessionManager.getUserName(), userName)){
196+
binding.swipeRefreshLayout.setOnRefreshListener(() -> {
197+
contributionsListPresenter.refreshList(binding.swipeRefreshLayout);
198+
});
199+
} else {
200+
binding.swipeRefreshLayout.setEnabled(false);
201+
}
202+
194203
return binding.getRoot();
195204
}
196205

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListPresenter.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88
import androidx.paging.DataSource.Factory;
99
import androidx.paging.LivePagedListBuilder;
1010
import androidx.paging.PagedList;
11+
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
1112
import fr.free.nrw.commons.contributions.ContributionsListContract.UserActionListener;
12-
import fr.free.nrw.commons.di.CommonsApplicationModule;
1313
import io.reactivex.Scheduler;
1414
import io.reactivex.disposables.CompositeDisposable;
15-
import java.util.Arrays;
1615
import java.util.Collections;
1716
import javax.inject.Inject;
1817
import javax.inject.Named;
18+
import kotlin.Unit;
19+
import kotlin.jvm.functions.Function0;
1920

2021
/**
2122
* The presenter class for Contributions
@@ -95,4 +96,17 @@ public void onDetachView() {
9596
contributionBoundaryCallback.dispose();
9697
}
9798

99+
/**
100+
* It is used to refresh list.
101+
*
102+
* @param swipeRefreshLayout used to stop refresh animation when
103+
* refresh finishes.
104+
*/
105+
@Override
106+
public void refreshList(final SwipeRefreshLayout swipeRefreshLayout) {
107+
contributionBoundaryCallback.refreshList(() -> {
108+
swipeRefreshLayout.setRefreshing(false);
109+
return Unit.INSTANCE;
110+
});
111+
}
98112
}
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,129 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3-
xmlns:app="http://schemas.android.com/apk/res-auto"
4-
xmlns:tools="http://schemas.android.com/tools"
5-
android:orientation="vertical"
2+
3+
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
4+
xmlns:app="http://schemas.android.com/apk/res-auto"
5+
xmlns:tools="http://schemas.android.com/tools"
6+
android:id="@+id/swipe_refresh_layout"
7+
android:layout_width="match_parent"
8+
android:layout_height="match_parent">
9+
10+
<RelativeLayout
611
android:layout_width="match_parent"
712
android:layout_height="match_parent"
813
android:background="?attr/contributionsListBackground"
9-
>
14+
android:orientation="vertical">
15+
1016

1117
<TextView
12-
android:id="@+id/noContributionsYet"
13-
android:layout_width="match_parent"
14-
android:layout_height="wrap_content"
15-
android:text="@string/no_uploads"
16-
android:gravity="center"
17-
android:layout_centerInParent="true"
18-
android:visibility="gone"
19-
android:layout_marginRight="@dimen/tiny_gap"
20-
android:layout_marginEnd="@dimen/tiny_gap"
21-
/>
18+
android:id="@+id/noContributionsYet"
19+
android:layout_width="match_parent"
20+
android:layout_height="wrap_content"
21+
android:layout_centerInParent="true"
22+
android:layout_marginEnd="@dimen/tiny_gap"
23+
android:layout_marginRight="@dimen/tiny_gap"
24+
android:gravity="center"
25+
android:text="@string/no_uploads"
26+
android:visibility="gone" />
2227

2328
<ProgressBar
2429
android:id="@+id/loadingContributionsProgressBar"
2530
android:layout_width="wrap_content"
2631
android:layout_height="wrap_content"
2732
android:layout_centerInParent="true"
28-
android:visibility="gone"
29-
/>
33+
android:visibility="gone" />
3034

3135
<RelativeLayout
3236
android:layout_width="match_parent"
3337
android:layout_height="match_parent"
3438
android:orientation="vertical">
3539

36-
<androidx.appcompat.widget.AppCompatTextView
37-
android:id="@+id/tv_contributions_of_user"
38-
style="@style/MediaDetailTextLabel"
39-
tools:text="Contributions of user : Ashish"
40-
android:layout_width="match_parent"
41-
android:layout_height="wrap_content"
42-
android:padding="10dp"
43-
tools:visibility="visible"
44-
android:visibility="gone" />
45-
46-
<androidx.recyclerview.widget.RecyclerView
47-
android:id="@+id/contributionsList"
48-
android:layout_width="match_parent"
49-
android:layout_height="match_parent"
50-
android:layout_below="@id/tv_contributions_of_user"
51-
android:scrollbars="vertical"
52-
android:fadeScrollbars="true"
53-
android:scrollbarThumbVertical="@color/primaryColor"
54-
android:scrollbarSize="@dimen/dimen_6"/>
40+
<androidx.appcompat.widget.AppCompatTextView
41+
android:id="@+id/tv_contributions_of_user"
42+
style="@style/MediaDetailTextLabel"
43+
android:layout_width="match_parent"
44+
android:layout_height="wrap_content"
45+
android:padding="10dp"
46+
android:visibility="gone"
47+
tools:text="Contributions of user : Ashish"
48+
tools:visibility="visible" />
49+
50+
<androidx.recyclerview.widget.RecyclerView
51+
android:id="@+id/contributionsList"
52+
android:layout_width="match_parent"
53+
android:layout_height="match_parent"
54+
android:layout_below="@id/tv_contributions_of_user"
55+
android:fadeScrollbars="true"
56+
android:scrollbarSize="@dimen/dimen_6"
57+
android:scrollbarThumbVertical="@color/primaryColor"
58+
android:scrollbars="vertical" />
5559
</RelativeLayout>
5660

5761
<LinearLayout
58-
android:id="@+id/fab_layout"
62+
android:id="@+id/fab_layout"
63+
android:layout_width="wrap_content"
64+
android:layout_height="wrap_content"
65+
android:layout_alignParentEnd="true"
66+
android:layout_alignParentRight="true"
67+
android:layout_alignParentBottom="true"
68+
android:layout_marginRight="@dimen/medium_height"
69+
android:layout_marginBottom="@dimen/activity_margin_horizontal"
70+
android:gravity="center"
71+
android:orientation="vertical">
72+
73+
<com.google.android.material.floatingactionbutton.FloatingActionButton
74+
android:id="@+id/fab_camera"
75+
android:layout_width="wrap_content"
76+
android:layout_height="wrap_content"
77+
android:contentDescription="@string/add_contribution_from_camera"
78+
android:tint="@color/button_blue"
79+
android:visibility="gone"
80+
app:backgroundTint="@color/main_background_light"
81+
app:elevation="@dimen/tiny_margin"
82+
app:fabSize="mini"
83+
app:srcCompat="@drawable/ic_photo_camera_white_24dp"
84+
app:useCompatPadding="true" />
85+
86+
<com.google.android.material.floatingactionbutton.FloatingActionButton
87+
android:id="@+id/fab_gallery"
88+
android:layout_width="wrap_content"
89+
android:layout_height="wrap_content"
90+
android:contentDescription="@string/add_contribution_from_photos"
91+
android:tint="@color/button_blue"
92+
android:visibility="gone"
93+
app:backgroundTint="@color/main_background_light"
94+
app:elevation="@dimen/tiny_margin"
95+
app:fabSize="mini"
96+
app:srcCompat="@drawable/ic_photo_white_24dp"
97+
app:useCompatPadding="true" />
98+
99+
<com.google.android.material.floatingactionbutton.FloatingActionButton
100+
android:id="@+id/fab_custom_gallery"
101+
android:layout_width="wrap_content"
102+
android:layout_height="wrap_content"
103+
android:background="@drawable/commons"
104+
android:contentDescription="@string/add_contribution_from_contributions_gallery"
105+
android:tint="@color/button_blue"
106+
android:visibility="gone"
107+
app:backgroundTint="@color/main_background_light"
108+
app:elevation="@dimen/tiny_margin"
109+
app:fabSize="mini"
110+
app:srcCompat="@drawable/ic_custom_image_picker"
111+
app:useCompatPadding="true" />
112+
113+
<com.google.android.material.floatingactionbutton.FloatingActionButton
114+
android:id="@+id/fab_plus"
59115
android:layout_width="wrap_content"
60116
android:layout_height="wrap_content"
61-
android:layout_alignParentBottom="true"
62-
android:layout_alignParentEnd="true"
63-
android:layout_alignParentRight="true"
64-
android:layout_marginRight="@dimen/medium_height"
65-
android:layout_marginBottom="@dimen/activity_margin_horizontal"
66-
android:orientation="vertical"
67-
android:gravity="center"
68-
>
69-
70-
<com.google.android.material.floatingactionbutton.FloatingActionButton
71-
android:id="@+id/fab_camera"
72-
android:layout_width="wrap_content"
73-
android:layout_height="wrap_content"
74-
android:contentDescription="@string/add_contribution_from_camera"
75-
android:tint="@color/button_blue"
76-
android:visibility="gone"
77-
app:backgroundTint="@color/main_background_light"
78-
app:elevation="@dimen/tiny_margin"
79-
app:fabSize="mini"
80-
app:srcCompat="@drawable/ic_photo_camera_white_24dp"
81-
app:useCompatPadding="true" />
82-
83-
<com.google.android.material.floatingactionbutton.FloatingActionButton
84-
android:id="@+id/fab_gallery"
85-
android:layout_width="wrap_content"
86-
android:layout_height="wrap_content"
87-
android:contentDescription="@string/add_contribution_from_photos"
88-
android:tint="@color/button_blue"
89-
android:visibility="gone"
90-
app:backgroundTint="@color/main_background_light"
91-
app:elevation="@dimen/tiny_margin"
92-
app:fabSize="mini"
93-
app:srcCompat="@drawable/ic_photo_white_24dp"
94-
app:useCompatPadding="true" />
95-
96-
<com.google.android.material.floatingactionbutton.FloatingActionButton
97-
android:id="@+id/fab_custom_gallery"
98-
android:layout_width="wrap_content"
99-
android:layout_height="wrap_content"
100-
android:background="@drawable/commons"
101-
android:contentDescription="@string/add_contribution_from_contributions_gallery"
102-
android:tint="@color/button_blue"
103-
android:visibility="gone"
104-
app:backgroundTint="@color/main_background_light"
105-
app:elevation="@dimen/tiny_margin"
106-
app:fabSize="mini"
107-
app:srcCompat="@drawable/ic_custom_image_picker"
108-
app:useCompatPadding="true" />
109-
110-
<com.google.android.material.floatingactionbutton.FloatingActionButton
111-
android:id="@+id/fab_plus"
112-
android:layout_width="wrap_content"
113-
android:layout_height="wrap_content"
114-
android:contentDescription="@string/add_new_contribution"
115-
android:gravity="center_vertical"
116-
android:visibility="visible"
117-
app:backgroundTint="@color/status_bar_blue"
118-
app:elevation="@dimen/tiny_margin"
119-
app:srcCompat="@drawable/ic_add_white_24dp"
120-
app:useCompatPadding="true" />
117+
android:contentDescription="@string/add_new_contribution"
118+
android:gravity="center_vertical"
119+
android:visibility="visible"
120+
app:backgroundTint="@color/status_bar_blue"
121+
app:elevation="@dimen/tiny_margin"
122+
app:srcCompat="@drawable/ic_add_white_24dp"
123+
app:useCompatPadding="true" />
121124

122125
</LinearLayout>
123126

124-
</RelativeLayout>
127+
</RelativeLayout>
125128

129+
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

0 commit comments

Comments
 (0)