From 8e3a41b06ff02b9eff295eb5923ad9210334d2c0 Mon Sep 17 00:00:00 2001 From: "adi.bk" Date: Wed, 31 May 2017 19:19:51 -0700 Subject: [PATCH] - Add filter for user repositories fragment - new layout and modifications to rest api - string resources --- .../data/dao/model/FilterOptionsModel.java | 127 ++++++++++++++ .../data/service/UserRestService.java | 7 +- .../profile/repos/ProfileRepoFilterMvp.java | 31 ++++ .../repos/ProfileRepoFilterPresenter.java | 64 +++++++ .../ProfileReposFilterBottomSheetDialog.java | 111 +++++++++++- .../profile/repos/ProfileReposFragment.java | 29 +++- .../profile/repos/ProfileReposMvp.java | 4 + .../profile/repos/ProfileReposPresenter.java | 32 +++- .../layout-land/filter_bottom_sheet.xml | 164 ++++++++++++++---- .../layout/filter_bottom_sheet.xml | 141 +++++++++++++++ app/src/main/res/values/strings.xml | 7 +- debug_gradle.properties | 4 +- 12 files changed, 669 insertions(+), 52 deletions(-) create mode 100644 app/src/main/java/com/fastaccess/data/dao/model/FilterOptionsModel.java create mode 100644 app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileRepoFilterMvp.java create mode 100644 app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileRepoFilterPresenter.java create mode 100644 app/src/main/res/layouts/main_layouts/layout/filter_bottom_sheet.xml diff --git a/app/src/main/java/com/fastaccess/data/dao/model/FilterOptionsModel.java b/app/src/main/java/com/fastaccess/data/dao/model/FilterOptionsModel.java new file mode 100644 index 00000000..07159d5a --- /dev/null +++ b/app/src/main/java/com/fastaccess/data/dao/model/FilterOptionsModel.java @@ -0,0 +1,127 @@ +package com.fastaccess.data.dao.model; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by adibk on 5/19/17. + */ + +public class FilterOptionsModel implements Parcelable { + + private static final String TYPE = "type"; + private static final String SORT = "sort"; + private static final String DIRECTION = "direction"; + + private String type = "All"; + private String sort = "Pushed"; + private String sortDirection = "descending"; + private Map queryMap; + + private List typesList = new ArrayList<>(Arrays.asList("All", "Owner", "Public", "Private", "Member")); + private List sortOptionsList = new ArrayList<>(Arrays.asList("Pushed", "Created", "Updated", "Full Name")); + private List sortDirectionList = new ArrayList<>(Arrays.asList("Descending", "Ascending")); + + public FilterOptionsModel() { + } + + protected FilterOptionsModel(Parcel in) { + type = in.readString(); + sort = in.readString(); + sortDirection = in.readString(); + typesList = in.createStringArrayList(); + sortOptionsList = in.createStringArrayList(); + sortDirectionList = in.createStringArrayList(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public FilterOptionsModel createFromParcel(Parcel in) { + return new FilterOptionsModel(in); + } + + @Override + public FilterOptionsModel[] newArray(int size) { + return new FilterOptionsModel[size]; + } + }; + + public void setType(String type) { + this.type = type; + } + + public void setSort(String sort) { + this.sort = sort; + } + + public void setsortDirection(String sortDirection) { + this.sortDirection = sortDirection; + } + + public Map getQueryMap() { + if (queryMap == null) { + queryMap = new HashMap<>(); + } else { + queryMap.clear(); + } + queryMap.put(TYPE, type.toLowerCase()); + if (sort.contains(" ")) { + //full name should be full_name + queryMap.put(SORT, sort.replace(" ", "_").toLowerCase()); + } else { + queryMap.put(SORT, sort.toLowerCase()); + } + if (sortDirection.equals(sortDirectionList.get(0))) { + queryMap.put(DIRECTION, sortDirection.toLowerCase().substring(0, 4)); + } else { + queryMap.put(DIRECTION, sortDirection.toLowerCase().substring(0, 3)); + } + + return queryMap; + } + + public int getSelectedTypeIndex() { + return typesList.indexOf(type); + } + + public int getSelectedSortOptionIndex() { + return sortOptionsList.indexOf(sort); + } + + public int getSelectedSortDirectionIndex() { + return sortDirectionList.indexOf(sortDirection); + } + + public List getTypesList() { + return typesList; + } + + public List getSortOptionList() { + return sortOptionsList; + } + + public List getSortDirectionList() { + return sortDirectionList; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(type); + dest.writeString(sort); + dest.writeString(sortDirection); + dest.writeStringList(typesList); + dest.writeStringList(sortOptionsList); + dest.writeStringList(sortDirectionList); + } +} diff --git a/app/src/main/java/com/fastaccess/data/service/UserRestService.java b/app/src/main/java/com/fastaccess/data/service/UserRestService.java index ce0927e7..97c22adf 100644 --- a/app/src/main/java/com/fastaccess/data/service/UserRestService.java +++ b/app/src/main/java/com/fastaccess/data/service/UserRestService.java @@ -8,6 +8,8 @@ import com.fastaccess.data.dao.model.Login; import com.fastaccess.data.dao.model.Repo; import com.fastaccess.data.dao.model.User; +import java.util.Map; + import io.reactivex.Observable; import retrofit2.Response; import retrofit2.http.DELETE; @@ -15,6 +17,7 @@ import retrofit2.http.GET; import retrofit2.http.PUT; import retrofit2.http.Path; import retrofit2.http.Query; +import retrofit2.http.QueryMap; import retrofit2.http.Url; @@ -34,8 +37,8 @@ public interface UserRestService { @GET("users/{username}/repos?affiliation=owner,collaborator&sort=pushed&direction=desc") Observable> getRepos(@Path("username") @NonNull String username, @Query("page") int page); - @GET("/user/repos?affiliation=owner,collaborator&sort=pushed&direction=desc") - Observable> getRepos(@Query("page") int page); + @GET("/user/repos") + Observable> getRepos(@QueryMap(encoded=true) Map filterParams, @Query(value = "page", encoded = true) int page); @GET("users/{username}/starred") Observable> getStarred(@Path("username") @NonNull String username, @Query("page") int page); diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileRepoFilterMvp.java b/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileRepoFilterMvp.java new file mode 100644 index 00000000..315364b3 --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileRepoFilterMvp.java @@ -0,0 +1,31 @@ +package com.fastaccess.ui.modules.profile.repos; + +import com.fastaccess.ui.base.mvp.BaseMvp; + +import java.util.List; + +/** + * Created by adibk on 5/29/17. + */ + +public interface ProfileRepoFilterMvp { + + interface View extends BaseMvp.FAView { + + } + + interface Presenter { + + void onTypeSelected(String selectedType); + void onSortOptionSelected(String selectedSortOption); + void onSortDirectionSelected(String selectedSortDirection); + + int getTypePosition(); + int getSortOptionPosition(); + int getSortDirectionPosition(); + + List getTypesList(); + List getSortOptionList(); + List getSortDirectionList(); + } +} diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileRepoFilterPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileRepoFilterPresenter.java new file mode 100644 index 00000000..8ed0e18d --- /dev/null +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileRepoFilterPresenter.java @@ -0,0 +1,64 @@ +package com.fastaccess.ui.modules.profile.repos; + +import com.fastaccess.data.dao.model.FilterOptionsModel; +import com.fastaccess.ui.base.mvp.presenter.BasePresenter; + +import java.util.List; + +/** + * Created by adibk on 5/29/17. + */ + +public class ProfileRepoFilterPresenter extends BasePresenter implements ProfileRepoFilterMvp.Presenter { + + private FilterOptionsModel filterOptions = new FilterOptionsModel(); + + @Override + public void onTypeSelected(String selectedType) { + filterOptions.setType(selectedType); + } + + @Override + public void onSortOptionSelected(String selectedSortOption) { + filterOptions.setSort(selectedSortOption); + } + + @Override + public void onSortDirectionSelected(String selectedSortDirection) { + filterOptions.setsortDirection(selectedSortDirection); + } + + public FilterOptionsModel getFilterOptions() { + return filterOptions; + } + + @Override + public int getTypePosition() { + return filterOptions.getSelectedTypeIndex(); + } + + @Override + public int getSortOptionPosition() { + return filterOptions.getSelectedSortOptionIndex(); + } + + @Override + public int getSortDirectionPosition() { + return filterOptions.getSelectedSortDirectionIndex(); + } + + @Override + public List getTypesList() { + return filterOptions.getTypesList(); + } + + @Override + public List getSortOptionList() { + return filterOptions.getSortOptionList(); + } + + @Override + public List getSortDirectionList() { + return filterOptions.getSortDirectionList(); + } +} diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposFilterBottomSheetDialog.java b/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposFilterBottomSheetDialog.java index 59b4fa30..6f3d0d3d 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposFilterBottomSheetDialog.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposFilterBottomSheetDialog.java @@ -1,14 +1,117 @@ package com.fastaccess.ui.modules.profile.repos; +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.Spinner; + +import com.fastaccess.R; +import com.fastaccess.data.dao.model.FilterOptionsModel; import com.fastaccess.ui.base.BaseBottomSheetDialog; -/** - * Created by adibk on 5/8/17. - */ +import butterknife.BindView; +import butterknife.OnClick; public class ProfileReposFilterBottomSheetDialog extends BaseBottomSheetDialog { + + private static final String FILTER = "filter"; + + @BindView(R.id.type_selection) Spinner typeSelectionSpinner; + @BindView(R.id.sort_selection) Spinner sortSelectionSpinner; + @BindView(R.id.filter_sheet_apply_btn) Button applyBtn; + @BindView(R.id.sort_direction_selection) Spinner sortDirectionSpinner; + + private ProfileReposFilterChangeListener listener; + private FilterOptionsModel currentFilterOptions; + @Override protected int layoutRes() { - return 0; + return R.layout.filter_bottom_sheet; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + ArrayAdapter typesAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, currentFilterOptions.getTypesList()); + ArrayAdapter sortOptionsAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, currentFilterOptions.getSortOptionList()); + ArrayAdapter sortDirectionAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, currentFilterOptions.getSortDirectionList()); + typeSelectionSpinner.setAdapter(typesAdapter); + sortSelectionSpinner.setAdapter(sortOptionsAdapter); + sortDirectionSpinner.setAdapter(sortDirectionAdapter); + + typeSelectionSpinner.setSelection(currentFilterOptions.getSelectedTypeIndex()); + sortSelectionSpinner.setSelection(currentFilterOptions.getSelectedSortOptionIndex()); + sortDirectionSpinner.setSelection(currentFilterOptions.getSelectedSortDirectionIndex()); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + listener = ((ProfileReposFragment) getParentFragment()); + } + + @Override + public void onDetach() { + super.onDetach(); + listener = null; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + if (savedInstanceState != null) { + setCurrentFilterOptions(((FilterOptionsModel) savedInstanceState.get(FILTER))); + } + return super.onCreateView(inflater, container, savedInstanceState); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelable(FILTER, currentFilterOptions); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @OnClick(R.id.filter_sheet_apply_btn) public void onApply() { + if (listener != null) { + listener.onTypeSelected((String) typeSelectionSpinner.getSelectedItem()); + listener.onSortOptionSelected((String) sortSelectionSpinner.getSelectedItem()); + listener.onSortDirectionSelected((String) sortDirectionSpinner.getSelectedItem()); + listener.onFilterApply(); + dismiss(); + } + } + + @OnClick(R.id.filter_sheet_reset_btn) public void onReset() { + typeSelectionSpinner.setSelection(0); + sortDirectionSpinner.setSelection(0); + sortSelectionSpinner.setSelection(0); + } + + @Override + public void dismiss() { + currentFilterOptions = null; + super.dismiss(); + } + + public void setCurrentFilterOptions(FilterOptionsModel currentFilterOptions) { + this.currentFilterOptions = currentFilterOptions; + } + + public interface ProfileReposFilterChangeListener { + void onFilterApply(); + void onTypeSelected(String selectedType); + void onSortOptionSelected(String selectedSortOption); + void onSortDirectionSelected(String selectedSortDirection); } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposFragment.java b/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposFragment.java index e18b81a9..846b8e53 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposFragment.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposFragment.java @@ -25,13 +25,14 @@ import butterknife.BindView; * Created by Kosh on 03 Dec 2016, 3:56 PM */ -public class ProfileReposFragment extends BaseFragment implements ProfileReposMvp.View { +public class ProfileReposFragment extends BaseFragment implements ProfileReposMvp.View, ProfileReposFilterBottomSheetDialog.ProfileReposFilterChangeListener { @BindView(R.id.recycler) DynamicRecyclerView recycler; @BindView(R.id.refresh) SwipeRefreshLayout refresh; @BindView(R.id.stateLayout) StateLayout stateLayout; private OnLoadMore onLoadMore; private ReposAdapter adapter; + private ProfileReposFilterBottomSheetDialog dialog; public static ProfileReposFragment newInstance(@NonNull String username) { ProfileReposFragment view = new ProfileReposFragment(); @@ -53,7 +54,7 @@ public class ProfileReposFragment extends BaseFragment getRepos(); void onWorkOffline(@NonNull String login); + void onFilterApply(); + void onTypeSelected(String selectedType); + void onSortOptionSelected(String selectedSortOption); + void onSortDirectionSelected(String selectedSortDirection); } } diff --git a/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposPresenter.java b/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposPresenter.java index 06684a41..9c7d66f7 100644 --- a/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposPresenter.java +++ b/app/src/main/java/com/fastaccess/ui/modules/profile/repos/ProfileReposPresenter.java @@ -6,6 +6,7 @@ import android.text.TextUtils; import android.view.View; import com.fastaccess.data.dao.NameParser; +import com.fastaccess.data.dao.model.FilterOptionsModel; import com.fastaccess.data.dao.model.Login; import com.fastaccess.data.dao.model.Repo; import com.fastaccess.helper.RxHelper; @@ -24,8 +25,10 @@ class ProfileReposPresenter extends BasePresenter implemen private ArrayList repos = new ArrayList<>(); private int page; private int previousTotal; + private String username; private int lastPage = Integer.MAX_VALUE; private String currentLoggedIn; + private FilterOptionsModel filterOptions = new FilterOptionsModel(); @Override public int getCurrentPage() { return page; @@ -59,6 +62,7 @@ class ProfileReposPresenter extends BasePresenter implemen if (parameter == null) { throw new NullPointerException("Username is null"); } + username = parameter; if (page == 1) { lastPage = Integer.MAX_VALUE; sendToView(view -> view.getLoadMore().reset()); @@ -68,8 +72,8 @@ class ProfileReposPresenter extends BasePresenter implemen sendToView(ProfileReposMvp.View::hideProgress); return; } - makeRestCall(TextUtils.equals(currentLoggedIn, parameter) - ? RestProvider.getUserService().getRepos(page) + makeRestCall(TextUtils.equals(currentLoggedIn, username) + ? RestProvider.getUserService().getRepos(filterOptions.getQueryMap(), page) : RestProvider.getUserService().getRepos(parameter, page), repoModelPageable -> { lastPage = repoModelPageable.getLast(); @@ -98,4 +102,28 @@ class ProfileReposPresenter extends BasePresenter implemen } @Override public void onItemLongClick(int position, View v, Repo item) {} + + public FilterOptionsModel getFilterOptions() { + return filterOptions; + } + + @Override + public void onFilterApply() { + onCallApi(1, username); + } + + @Override + public void onTypeSelected(String selectedType) { + filterOptions.setType(selectedType); + } + + @Override + public void onSortOptionSelected(String selectedSortOption) { + filterOptions.setSort(selectedSortOption); + } + + @Override + public void onSortDirectionSelected(String selectedSortDirection) { + filterOptions.setsortDirection(selectedSortDirection); + } } diff --git a/app/src/main/res/layouts/main_layouts/layout-land/filter_bottom_sheet.xml b/app/src/main/res/layouts/main_layouts/layout-land/filter_bottom_sheet.xml index 271d2d06..6a7d4d87 100644 --- a/app/src/main/res/layouts/main_layouts/layout-land/filter_bottom_sheet.xml +++ b/app/src/main/res/layouts/main_layouts/layout-land/filter_bottom_sheet.xml @@ -6,48 +6,136 @@ android:layout_height="wrap_content" android:orientation="vertical"> - + android:orientation="vertical"> - + android:background="@color/material_blue_accent_400" + android:elevation="4dp"> -