Skip to content

Commit 94952f1

Browse files
[GSoC] Added Leaderboard Filters (#3902)
* Attempt to add filters * Basic Filter Working * Filter Improved * Filter Completed
1 parent baee56e commit 94952f1

File tree

8 files changed

+222
-23
lines changed

8 files changed

+222
-23
lines changed

app/src/main/java/fr/free/nrw/commons/profile/leaderboard/DataSourceClass.java

+13-6
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LOADED;
44
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LOADING;
5-
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.PAGE_SIZE;
6-
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.START_OFFSET;
75

86
import androidx.annotation.NonNull;
97
import androidx.lifecycle.MutableLiveData;
@@ -20,10 +18,19 @@ public class DataSourceClass extends PageKeyedDataSource<Integer, LeaderboardLis
2018
private SessionManager sessionManager;
2119
private MutableLiveData<String> progressLiveStatus;
2220
private CompositeDisposable compositeDisposable = new CompositeDisposable();
21+
private String duration;
22+
private String category;
23+
private int limit;
24+
private int offset;
2325

24-
public DataSourceClass(OkHttpJsonApiClient okHttpJsonApiClient,SessionManager sessionManager) {
26+
public DataSourceClass(OkHttpJsonApiClient okHttpJsonApiClient,SessionManager sessionManager,
27+
String duration, String category, int limit, int offset) {
2528
this.okHttpJsonApiClient = okHttpJsonApiClient;
2629
this.sessionManager = sessionManager;
30+
this.duration = duration;
31+
this.category = category;
32+
this.limit = limit;
33+
this.offset = offset;
2734
progressLiveStatus = new MutableLiveData<>();
2835
}
2936

@@ -38,7 +45,7 @@ public void loadInitial(@NonNull LoadInitialParams<Integer> params,
3845

3946
compositeDisposable.add(okHttpJsonApiClient
4047
.getLeaderboard(Objects.requireNonNull(sessionManager.getCurrentAccount()).name,
41-
"all_time", "upload", String.valueOf(PAGE_SIZE), String.valueOf(START_OFFSET))
48+
duration, category, String.valueOf(limit), String.valueOf(offset))
4249
.doOnSubscribe(disposable -> {
4350
compositeDisposable.add(disposable);
4451
progressLiveStatus.postValue(LOADING);
@@ -68,15 +75,15 @@ public void loadAfter(@NonNull LoadParams<Integer> params,
6875
@NonNull LoadCallback<Integer, LeaderboardList> callback) {
6976
compositeDisposable.add(okHttpJsonApiClient
7077
.getLeaderboard(Objects.requireNonNull(sessionManager.getCurrentAccount()).name,
71-
"all_time", "upload", String.valueOf(PAGE_SIZE), String.valueOf(params.key))
78+
duration, category, String.valueOf(limit), String.valueOf(params.key))
7279
.doOnSubscribe(disposable -> {
7380
compositeDisposable.add(disposable);
7481
progressLiveStatus.postValue(LOADING);
7582
}).subscribe(
7683
response -> {
7784
if (response != null && response.getStatus() == 200) {
7885
progressLiveStatus.postValue(LOADED);
79-
callback.onResult(response.getLeaderboardList(), params.key + PAGE_SIZE);
86+
callback.onResult(response.getLeaderboardList(), params.key + limit);
8087
}
8188
},
8289
t -> {

app/src/main/java/fr/free/nrw/commons/profile/leaderboard/DataSourceFactory.java

+37-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,42 @@ public class DataSourceFactory extends DataSource.Factory<Integer, LeaderboardLi
1212
private OkHttpJsonApiClient okHttpJsonApiClient;
1313
private CompositeDisposable compositeDisposable;
1414
private SessionManager sessionManager;
15+
private String duration;
16+
private String category;
17+
private int limit;
18+
private int offset;
19+
20+
public String getDuration() {
21+
return duration;
22+
}
23+
24+
public void setDuration(final String duration) {
25+
this.duration = duration;
26+
}
27+
28+
public String getCategory() {
29+
return category;
30+
}
31+
32+
public void setCategory(final String category) {
33+
this.category = category;
34+
}
35+
36+
public int getLimit() {
37+
return limit;
38+
}
39+
40+
public void setLimit(final int limit) {
41+
this.limit = limit;
42+
}
43+
44+
public int getOffset() {
45+
return offset;
46+
}
47+
48+
public void setOffset(final int offset) {
49+
this.offset = offset;
50+
}
1551

1652
public DataSourceFactory(OkHttpJsonApiClient okHttpJsonApiClient, CompositeDisposable compositeDisposable,
1753
SessionManager sessionManager) {
@@ -27,7 +63,7 @@ public MutableLiveData<DataSourceClass> getMutableLiveData() {
2763

2864
@Override
2965
public DataSource<Integer, LeaderboardList> create() {
30-
DataSourceClass dataSourceClass = new DataSourceClass(okHttpJsonApiClient, sessionManager);
66+
DataSourceClass dataSourceClass = new DataSourceClass(okHttpJsonApiClient, sessionManager, duration, category, limit, offset);
3167
liveData.postValue(dataSourceClass);
3268
return dataSourceClass;
3369
}

app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardFragment.java

+86-11
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@
22

33
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LOADED;
44
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LOADING;
5+
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.PAGE_SIZE;
6+
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.START_OFFSET;
57

68
import android.accounts.Account;
79
import android.os.Bundle;
810
import android.view.LayoutInflater;
911
import android.view.View;
1012
import android.view.ViewGroup;
13+
import android.widget.AdapterView;
14+
import android.widget.AdapterView.OnItemSelectedListener;
15+
import android.widget.ArrayAdapter;
1116
import android.widget.ProgressBar;
17+
import android.widget.Spinner;
1218
import androidx.lifecycle.ViewModelProvider;
1319
import androidx.recyclerview.widget.LinearLayoutManager;
1420
import androidx.recyclerview.widget.MergeAdapter;
@@ -35,6 +41,12 @@ public class LeaderboardFragment extends CommonsDaggerSupportFragment {
3541
@BindView(R.id.progressBar)
3642
ProgressBar progressBar;
3743

44+
@BindView(R.id.category_spinner)
45+
Spinner categorySpinner;
46+
47+
@BindView(R.id.duration_spinner)
48+
Spinner durationSpinner;
49+
3850
@Inject
3951
SessionManager sessionManager;
4052

@@ -48,32 +60,91 @@ public class LeaderboardFragment extends CommonsDaggerSupportFragment {
4860

4961
private CompositeDisposable compositeDisposable = new CompositeDisposable();
5062

63+
String duration;
64+
String category;
65+
int limit = PAGE_SIZE;
66+
int offset = START_OFFSET;
67+
5168
@Override
5269
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
5370
View rootView = inflater.inflate(R.layout.fragment_leaderboard, container, false);
5471
ButterKnife.bind(this, rootView);
72+
5573
progressBar.setVisibility(View.VISIBLE);
5674
hideLayouts();
57-
setLeaderboard();
75+
setSpinners();
76+
77+
String[] durationValues = getContext().getResources().getStringArray(R.array.leaderboard_duration_values);
78+
String[] categoryValues = getContext().getResources().getStringArray(R.array.leaderboard_category_values);
79+
80+
duration = durationValues[0];
81+
category = categoryValues[0];
82+
83+
setLeaderboard(duration, category, limit, offset);
84+
85+
durationSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
86+
@Override
87+
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
88+
89+
duration = durationValues[durationSpinner.getSelectedItemPosition()];
90+
refreshLeaderboard();
91+
}
92+
93+
@Override
94+
public void onNothingSelected(AdapterView<?> adapterView) {
95+
}
96+
});
97+
98+
categorySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
99+
@Override
100+
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
101+
category = categoryValues[categorySpinner.getSelectedItemPosition()];
102+
refreshLeaderboard();
103+
}
104+
105+
@Override
106+
public void onNothingSelected(AdapterView<?> adapterView) {
107+
}
108+
});
109+
58110
return rootView;
59111
}
60112

113+
private void refreshLeaderboard() {
114+
if (viewModel != null) {
115+
viewModel.refresh(duration, category, limit, offset);
116+
setLeaderboard(duration, category, limit, offset);
117+
}
118+
}
119+
120+
private void setSpinners() {
121+
ArrayAdapter<CharSequence> categoryAdapter = ArrayAdapter.createFromResource(getContext(),
122+
R.array.leaderboard_categories, android.R.layout.simple_spinner_item);
123+
categoryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
124+
categorySpinner.setAdapter(categoryAdapter);
125+
126+
ArrayAdapter<CharSequence> durationAdapter = ArrayAdapter.createFromResource(getContext(),
127+
R.array.leaderboard_durations, android.R.layout.simple_spinner_item);
128+
durationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
129+
durationSpinner.setAdapter(durationAdapter);
130+
}
131+
61132
/**
62133
* To call the API to get results
63134
* which then sets the views using setLeaderboardUser method
64135
*/
65-
private void setLeaderboard() {
136+
private void setLeaderboard(String duration, String category, int limit, int offset) {
66137
if (checkAccount()) {
67138
try {
68139
compositeDisposable.add(okHttpJsonApiClient
69140
.getLeaderboard(Objects.requireNonNull(sessionManager.getCurrentAccount()).name,
70-
"all_time", "upload", null, null)
141+
duration, category, null, null)
71142
.subscribeOn(Schedulers.io())
72143
.observeOn(AndroidSchedulers.mainThread())
73144
.subscribe(
74145
response -> {
75146
if (response != null && response.getStatus() == 200) {
76-
setViews(response);
147+
setViews(response, duration, category, limit, offset);
77148
}
78149
},
79150
t -> {
@@ -92,22 +163,22 @@ private void setLeaderboard() {
92163
* Set the views
93164
* @param response Leaderboard Response Object
94165
*/
95-
private void setViews(LeaderboardResponse response) {
166+
private void setViews(LeaderboardResponse response, String duration, String category, int limit, int offset) {
96167
viewModel = new ViewModelProvider(this, viewModelFactory).get(LeaderboardListViewModel.class);
168+
viewModel.setParams(duration, category, limit, offset);
97169
LeaderboardListAdapter leaderboardListAdapter = new LeaderboardListAdapter();
98170
UserDetailAdapter userDetailAdapter= new UserDetailAdapter(response);
99171
MergeAdapter mergeAdapter = new MergeAdapter(userDetailAdapter, leaderboardListAdapter);
100172
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
101173
leaderboardListRecyclerView.setLayoutManager(linearLayoutManager);
102174
leaderboardListRecyclerView.setAdapter(mergeAdapter);
103-
104175
viewModel.getListLiveData().observe(getViewLifecycleOwner(), leaderboardListAdapter::submitList);
105176
viewModel.getProgressLoadStatus().observe(getViewLifecycleOwner(), status -> {
106-
if (Objects.requireNonNull(status).equalsIgnoreCase(LOADING)) {
107-
showProgressBar();
108-
} else if (status.equalsIgnoreCase(LOADED)) {
109-
hideProgressBar();
110-
}
177+
if (Objects.requireNonNull(status).equalsIgnoreCase(LOADING)) {
178+
showProgressBar();
179+
} else if (status.equalsIgnoreCase(LOADED)) {
180+
hideProgressBar();
181+
}
111182
});
112183
}
113184

@@ -117,6 +188,8 @@ private void setViews(LeaderboardResponse response) {
117188
private void hideProgressBar() {
118189
if (progressBar != null) {
119190
progressBar.setVisibility(View.GONE);
191+
categorySpinner.setVisibility(View.VISIBLE);
192+
durationSpinner.setVisibility(View.VISIBLE);
120193
leaderboardListRecyclerView.setVisibility(View.VISIBLE);
121194
}
122195
}
@@ -134,6 +207,8 @@ private void showProgressBar() {
134207
* used to hide the layouts while fetching results from api
135208
*/
136209
private void hideLayouts(){
210+
categorySpinner.setVisibility(View.INVISIBLE);
211+
durationSpinner.setVisibility(View.INVISIBLE);
137212
leaderboardListRecyclerView.setVisibility(View.INVISIBLE);
138213
}
139214

app/src/main/java/fr/free/nrw/commons/profile/leaderboard/LeaderboardListViewModel.java

+20-3
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ public class LeaderboardListViewModel extends ViewModel {
1717
private DataSourceFactory dataSourceFactory;
1818
private LiveData<PagedList<LeaderboardList>> listLiveData;
1919
private CompositeDisposable compositeDisposable = new CompositeDisposable();
20-
2120
private LiveData<String> progressLoadStatus = new MutableLiveData<>();
2221

23-
public LeaderboardListViewModel(OkHttpJsonApiClient okHttpJsonApiClient, SessionManager sessionManager) {
24-
dataSourceFactory = new DataSourceFactory(okHttpJsonApiClient, compositeDisposable, sessionManager);
22+
public LeaderboardListViewModel(OkHttpJsonApiClient okHttpJsonApiClient, SessionManager
23+
sessionManager) {
24+
25+
dataSourceFactory = new DataSourceFactory(okHttpJsonApiClient,
26+
compositeDisposable, sessionManager);
2527
initializePaging();
2628
}
2729

@@ -42,6 +44,21 @@ private void initializePaging() {
4244

4345
}
4446

47+
public void refresh(String duration, String category, int limit, int offset) {
48+
dataSourceFactory.setDuration(duration);
49+
dataSourceFactory.setCategory(category);
50+
dataSourceFactory.setLimit(limit);
51+
dataSourceFactory.setOffset(offset);
52+
dataSourceFactory.getMutableLiveData().getValue().invalidate();
53+
}
54+
55+
public void setParams(String duration, String category, int limit, int offset) {
56+
dataSourceFactory.setDuration(duration);
57+
dataSourceFactory.setCategory(category);
58+
dataSourceFactory.setLimit(limit);
59+
dataSourceFactory.setOffset(offset);
60+
}
61+
4562
public LiveData<String> getProgressLoadStatus() {
4663
return progressLoadStatus;
4764
}

app/src/main/java/fr/free/nrw/commons/profile/leaderboard/ViewModelFactory.java

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public class ViewModelFactory implements ViewModelProvider.Factory {
1212
private OkHttpJsonApiClient okHttpJsonApiClient;
1313
private SessionManager sessionManager;
1414

15+
1516
@Inject
1617
public ViewModelFactory(OkHttpJsonApiClient okHttpJsonApiClient, SessionManager sessionManager) {
1718
this.okHttpJsonApiClient = okHttpJsonApiClient;

app/src/main/res/layout/fragment_leaderboard.xml

+34-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,44 @@
44
xmlns:android="http://schemas.android.com/apk/res/android"
55
xmlns:app="http://schemas.android.com/apk/res-auto"
66
android:layout_width="match_parent"
7-
android:layout_height="wrap_content">
7+
android:layout_height="match_parent">
8+
9+
<LinearLayout
10+
android:id="@+id/filters"
11+
android:layout_width="match_parent"
12+
android:layout_height="wrap_content"
13+
android:orientation="horizontal"
14+
android:weightSum="1"
15+
android:layout_margin="20dp"
16+
app:layout_constraintEnd_toEndOf="parent"
17+
app:layout_constraintStart_toStartOf="parent"
18+
app:layout_constraintTop_toTopOf="parent">
19+
20+
<Spinner
21+
android:layout_marginStart="60dp"
22+
android:id="@+id/duration_spinner"
23+
android:layout_width="match_parent"
24+
android:layout_weight="0.5"
25+
android:layout_height="match_parent" />
26+
27+
<Spinner
28+
android:layout_marginEnd="60dp"
29+
android:id="@+id/category_spinner"
30+
android:layout_width="match_parent"
31+
android:layout_weight="0.5"
32+
android:layout_height="match_parent" />
33+
34+
</LinearLayout>
835

936
<androidx.recyclerview.widget.RecyclerView
1037
android:id="@+id/leaderboard_list"
1138
android:layout_width="match_parent"
12-
android:layout_height="match_parent" />
39+
android:layout_height="0dp"
40+
android:layout_marginTop="10dp"
41+
app:layout_constraintBottom_toBottomOf="parent"
42+
app:layout_constraintEnd_toEndOf="parent"
43+
app:layout_constraintStart_toStartOf="parent"
44+
app:layout_constraintTop_toBottomOf="@+id/filters" />
1345

1446
<ProgressBar
1547
android:id="@+id/progressBar"

0 commit comments

Comments
 (0)