[GSoC] Added Leaderboard Filters (#3902)

* Attempt to add filters

* Basic Filter Working

* Filter Improved

* Filter Completed
This commit is contained in:
Madhur Gupta 2020-08-18 20:33:54 +05:30 committed by GitHub
parent baee56e392
commit 94952f1820
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 222 additions and 23 deletions

View file

@ -2,8 +2,6 @@ package fr.free.nrw.commons.profile.leaderboard;
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LOADED;
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LOADING;
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.PAGE_SIZE;
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.START_OFFSET;
import androidx.annotation.NonNull;
import androidx.lifecycle.MutableLiveData;
@ -20,10 +18,19 @@ public class DataSourceClass extends PageKeyedDataSource<Integer, LeaderboardLis
private SessionManager sessionManager;
private MutableLiveData<String> progressLiveStatus;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private String duration;
private String category;
private int limit;
private int offset;
public DataSourceClass(OkHttpJsonApiClient okHttpJsonApiClient,SessionManager sessionManager) {
public DataSourceClass(OkHttpJsonApiClient okHttpJsonApiClient,SessionManager sessionManager,
String duration, String category, int limit, int offset) {
this.okHttpJsonApiClient = okHttpJsonApiClient;
this.sessionManager = sessionManager;
this.duration = duration;
this.category = category;
this.limit = limit;
this.offset = offset;
progressLiveStatus = new MutableLiveData<>();
}
@ -38,7 +45,7 @@ public class DataSourceClass extends PageKeyedDataSource<Integer, LeaderboardLis
compositeDisposable.add(okHttpJsonApiClient
.getLeaderboard(Objects.requireNonNull(sessionManager.getCurrentAccount()).name,
"all_time", "upload", String.valueOf(PAGE_SIZE), String.valueOf(START_OFFSET))
duration, category, String.valueOf(limit), String.valueOf(offset))
.doOnSubscribe(disposable -> {
compositeDisposable.add(disposable);
progressLiveStatus.postValue(LOADING);
@ -68,7 +75,7 @@ public class DataSourceClass extends PageKeyedDataSource<Integer, LeaderboardLis
@NonNull LoadCallback<Integer, LeaderboardList> callback) {
compositeDisposable.add(okHttpJsonApiClient
.getLeaderboard(Objects.requireNonNull(sessionManager.getCurrentAccount()).name,
"all_time", "upload", String.valueOf(PAGE_SIZE), String.valueOf(params.key))
duration, category, String.valueOf(limit), String.valueOf(params.key))
.doOnSubscribe(disposable -> {
compositeDisposable.add(disposable);
progressLiveStatus.postValue(LOADING);
@ -76,7 +83,7 @@ public class DataSourceClass extends PageKeyedDataSource<Integer, LeaderboardLis
response -> {
if (response != null && response.getStatus() == 200) {
progressLiveStatus.postValue(LOADED);
callback.onResult(response.getLeaderboardList(), params.key + PAGE_SIZE);
callback.onResult(response.getLeaderboardList(), params.key + limit);
}
},
t -> {

View file

@ -12,6 +12,42 @@ public class DataSourceFactory extends DataSource.Factory<Integer, LeaderboardLi
private OkHttpJsonApiClient okHttpJsonApiClient;
private CompositeDisposable compositeDisposable;
private SessionManager sessionManager;
private String duration;
private String category;
private int limit;
private int offset;
public String getDuration() {
return duration;
}
public void setDuration(final String duration) {
this.duration = duration;
}
public String getCategory() {
return category;
}
public void setCategory(final String category) {
this.category = category;
}
public int getLimit() {
return limit;
}
public void setLimit(final int limit) {
this.limit = limit;
}
public int getOffset() {
return offset;
}
public void setOffset(final int offset) {
this.offset = offset;
}
public DataSourceFactory(OkHttpJsonApiClient okHttpJsonApiClient, CompositeDisposable compositeDisposable,
SessionManager sessionManager) {
@ -27,7 +63,7 @@ public class DataSourceFactory extends DataSource.Factory<Integer, LeaderboardLi
@Override
public DataSource<Integer, LeaderboardList> create() {
DataSourceClass dataSourceClass = new DataSourceClass(okHttpJsonApiClient, sessionManager);
DataSourceClass dataSourceClass = new DataSourceClass(okHttpJsonApiClient, sessionManager, duration, category, limit, offset);
liveData.postValue(dataSourceClass);
return dataSourceClass;
}

View file

@ -2,13 +2,19 @@ package fr.free.nrw.commons.profile.leaderboard;
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LOADED;
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.LOADING;
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.PAGE_SIZE;
import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.START_OFFSET;
import android.accounts.Account;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.ProgressBar;
import android.widget.Spinner;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.MergeAdapter;
@ -35,6 +41,12 @@ public class LeaderboardFragment extends CommonsDaggerSupportFragment {
@BindView(R.id.progressBar)
ProgressBar progressBar;
@BindView(R.id.category_spinner)
Spinner categorySpinner;
@BindView(R.id.duration_spinner)
Spinner durationSpinner;
@Inject
SessionManager sessionManager;
@ -48,32 +60,91 @@ public class LeaderboardFragment extends CommonsDaggerSupportFragment {
private CompositeDisposable compositeDisposable = new CompositeDisposable();
String duration;
String category;
int limit = PAGE_SIZE;
int offset = START_OFFSET;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_leaderboard, container, false);
ButterKnife.bind(this, rootView);
progressBar.setVisibility(View.VISIBLE);
hideLayouts();
setLeaderboard();
setSpinners();
String[] durationValues = getContext().getResources().getStringArray(R.array.leaderboard_duration_values);
String[] categoryValues = getContext().getResources().getStringArray(R.array.leaderboard_category_values);
duration = durationValues[0];
category = categoryValues[0];
setLeaderboard(duration, category, limit, offset);
durationSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
duration = durationValues[durationSpinner.getSelectedItemPosition()];
refreshLeaderboard();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
categorySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
category = categoryValues[categorySpinner.getSelectedItemPosition()];
refreshLeaderboard();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
return rootView;
}
private void refreshLeaderboard() {
if (viewModel != null) {
viewModel.refresh(duration, category, limit, offset);
setLeaderboard(duration, category, limit, offset);
}
}
private void setSpinners() {
ArrayAdapter<CharSequence> categoryAdapter = ArrayAdapter.createFromResource(getContext(),
R.array.leaderboard_categories, android.R.layout.simple_spinner_item);
categoryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
categorySpinner.setAdapter(categoryAdapter);
ArrayAdapter<CharSequence> durationAdapter = ArrayAdapter.createFromResource(getContext(),
R.array.leaderboard_durations, android.R.layout.simple_spinner_item);
durationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
durationSpinner.setAdapter(durationAdapter);
}
/**
* To call the API to get results
* which then sets the views using setLeaderboardUser method
*/
private void setLeaderboard() {
private void setLeaderboard(String duration, String category, int limit, int offset) {
if (checkAccount()) {
try {
compositeDisposable.add(okHttpJsonApiClient
.getLeaderboard(Objects.requireNonNull(sessionManager.getCurrentAccount()).name,
"all_time", "upload", null, null)
duration, category, null, null)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
response -> {
if (response != null && response.getStatus() == 200) {
setViews(response);
setViews(response, duration, category, limit, offset);
}
},
t -> {
@ -92,15 +163,15 @@ public class LeaderboardFragment extends CommonsDaggerSupportFragment {
* Set the views
* @param response Leaderboard Response Object
*/
private void setViews(LeaderboardResponse response) {
private void setViews(LeaderboardResponse response, String duration, String category, int limit, int offset) {
viewModel = new ViewModelProvider(this, viewModelFactory).get(LeaderboardListViewModel.class);
viewModel.setParams(duration, category, limit, offset);
LeaderboardListAdapter leaderboardListAdapter = new LeaderboardListAdapter();
UserDetailAdapter userDetailAdapter= new UserDetailAdapter(response);
MergeAdapter mergeAdapter = new MergeAdapter(userDetailAdapter, leaderboardListAdapter);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
leaderboardListRecyclerView.setLayoutManager(linearLayoutManager);
leaderboardListRecyclerView.setAdapter(mergeAdapter);
viewModel.getListLiveData().observe(getViewLifecycleOwner(), leaderboardListAdapter::submitList);
viewModel.getProgressLoadStatus().observe(getViewLifecycleOwner(), status -> {
if (Objects.requireNonNull(status).equalsIgnoreCase(LOADING)) {
@ -117,6 +188,8 @@ public class LeaderboardFragment extends CommonsDaggerSupportFragment {
private void hideProgressBar() {
if (progressBar != null) {
progressBar.setVisibility(View.GONE);
categorySpinner.setVisibility(View.VISIBLE);
durationSpinner.setVisibility(View.VISIBLE);
leaderboardListRecyclerView.setVisibility(View.VISIBLE);
}
}
@ -134,6 +207,8 @@ public class LeaderboardFragment extends CommonsDaggerSupportFragment {
* used to hide the layouts while fetching results from api
*/
private void hideLayouts(){
categorySpinner.setVisibility(View.INVISIBLE);
durationSpinner.setVisibility(View.INVISIBLE);
leaderboardListRecyclerView.setVisibility(View.INVISIBLE);
}

View file

@ -17,11 +17,13 @@ public class LeaderboardListViewModel extends ViewModel {
private DataSourceFactory dataSourceFactory;
private LiveData<PagedList<LeaderboardList>> listLiveData;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private LiveData<String> progressLoadStatus = new MutableLiveData<>();
public LeaderboardListViewModel(OkHttpJsonApiClient okHttpJsonApiClient, SessionManager sessionManager) {
dataSourceFactory = new DataSourceFactory(okHttpJsonApiClient, compositeDisposable, sessionManager);
public LeaderboardListViewModel(OkHttpJsonApiClient okHttpJsonApiClient, SessionManager
sessionManager) {
dataSourceFactory = new DataSourceFactory(okHttpJsonApiClient,
compositeDisposable, sessionManager);
initializePaging();
}
@ -42,6 +44,21 @@ public class LeaderboardListViewModel extends ViewModel {
}
public void refresh(String duration, String category, int limit, int offset) {
dataSourceFactory.setDuration(duration);
dataSourceFactory.setCategory(category);
dataSourceFactory.setLimit(limit);
dataSourceFactory.setOffset(offset);
dataSourceFactory.getMutableLiveData().getValue().invalidate();
}
public void setParams(String duration, String category, int limit, int offset) {
dataSourceFactory.setDuration(duration);
dataSourceFactory.setCategory(category);
dataSourceFactory.setLimit(limit);
dataSourceFactory.setOffset(offset);
}
public LiveData<String> getProgressLoadStatus() {
return progressLoadStatus;
}

View file

@ -12,6 +12,7 @@ public class ViewModelFactory implements ViewModelProvider.Factory {
private OkHttpJsonApiClient okHttpJsonApiClient;
private SessionManager sessionManager;
@Inject
public ViewModelFactory(OkHttpJsonApiClient okHttpJsonApiClient, SessionManager sessionManager) {
this.okHttpJsonApiClient = okHttpJsonApiClient;

View file

@ -4,12 +4,44 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/filters"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1"
android:layout_margin="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Spinner
android:layout_marginStart="60dp"
android:id="@+id/duration_spinner"
android:layout_width="match_parent"
android:layout_weight="0.5"
android:layout_height="match_parent" />
<Spinner
android:layout_marginEnd="60dp"
android:id="@+id/category_spinner"
android:layout_width="match_parent"
android:layout_weight="0.5"
android:layout_height="match_parent" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/leaderboard_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="0dp"
android:layout_marginTop="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/filters" />
<ProgressBar
android:id="@+id/progressBar"

View file

@ -46,4 +46,29 @@
<item>1</item>
<item>0</item>
</string-array>
<string-array name="leaderboard_categories">
<item>@string/leaderboard_upload</item>
<item>@string/leaderboard_used</item>
<item>@string/leaderboard_nearby</item>
</string-array>
<string-array name="leaderboard_category_values">
<item>upload</item>
<item>used</item>
<item>nearby</item>
</string-array>
<string-array name="leaderboard_durations">
<item>@string/leaderboard_weekly</item>
<item>@string/leaderboard_yearly</item>
<item>@string/leaderboard_all_time</item>
</string-array>
<string-array name="leaderboard_duration_values">
<item>weekly</item>
<item>yearly</item>
<item>all_time</item>
</string-array>
</resources>

View file

@ -666,4 +666,10 @@ Upload your first media by tapping on the add button.</string>
<string name="avatar_set_successfully">Avatar Set Successfully</string>
<string name="avatar_set_unsuccessfully">Error setting new avatar, please try again</string>
<string name="menu_set_avatar">Set as avatar</string>
<string name="leaderboard_yearly">Yearly</string>
<string name="leaderboard_weekly">Weekly</string>
<string name="leaderboard_all_time">All Time</string>
<string name="leaderboard_upload">Upload</string>
<string name="leaderboard_nearby">Nearby</string>
<string name="leaderboard_used">Used</string>
</resources>