From b3c11842f3524762db31fecaa1eadd30770fff46 Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Thu, 28 Nov 2019 11:22:32 +0300 Subject: [PATCH] Fixes #1450 Add filter to nearby (#3178) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add layout items for nearby filter list and filter item (cherry picked from commit b96f8a68ce1ebcea684f84500e4005940e648f70) * Edit nearby query (cherry picked from commit 1f3c8c8deb86586bf0394c80251d3be3d86b306e) * Add filter items to nearby parent fragment xml (cherry picked from commit d0beadd0e06291bf04e6676493db123df329d0e9) * Add icon for green marker (cherry picked from commit f65ca0387a004d94f71e9a9bcff464c184ef015f) * Add layout util file to organize layout utilities (cherry picked from commit 5c579392453ed7a2ed6ec576b4e150cdcc7c408d) * Add pic parameter to nearby result item (cherry picked from commit 86007e4bb6f5c13a067b0be3e5b441c67c7f265e) * Add pic parameter to place type (cherry picked from commit 25c358b67f0d64ce6e0c8b56933f90ea51ef11bf) * Add green marker styling (cherry picked from commit 929c92d887e1a2ac7e984c3a5677e77e2d24bab1) * Inıt search layouts on Nearby parent (cherry picked from commit 2ac38a1919ebe78fbde632b36a94101328656f32) * Style green markers at nearby controller (cherry picked from commit 3e08f39f8e623cd89b3e51b6eb6a25feaf42e23e) * Edit bookmark daos to include pic to tables (cherry picked from commit 48d69edf3b21995f7776e404c1888137e64d118a) * TODO foc bookmark dao item but works now (cherry picked from commit f7483997201243400a41ec8b5206e4367d792979) * Style nearby filter area (cherry picked from commit 6267e488b0591e17845b02cfa1347a761e32bff0) * fix style of filter tab (cherry picked from commit 5f843bf366f0169a5dcdbe90b5b14b44a1ed8dfc) * Add nearby list adapter (cherry picked from commit 56334afe03b1b2f0e0731e5039c54b45fcc1d1ca) * Current status, list size is working, visibility working, filter mechanism is ready (cherry picked from commit 7d75c9c589693aa977fbff453b2c02afbb679679) * Filtering works (cherry picked from commit 8a13cf7728288f5b56d096d39b157ef1f7fa8ba9) * Filter function works (cherry picked from commit 78368a2c0cb93c997659a46d3b26ebeb61720829) * Fix style issues (cherry picked from commit 2204f70255c25882bfefe8d85e808d2d7acf4619) * Add divider to recyclerview (cherry picked from commit c8100b55d752d80a2d0b272d0b252621697cccb6) * Hide bottom sheets accordingly (cherry picked from commit c5deba8b0b7262373814a108b6f61039a2aa153f) * Code cleanup (cherry picked from commit cf8f64f3cbc2db270f7ea5807594faaff41c9bcc) * Add actions to chips * Fetch destroyed information from servers * Add destroyed places icon * Make chip filter functions work * Revert irrelevant changes * Revert accidentally replaced strings * Remove unneeded lines * Remove only places expalanation from trings * Do not filter if nearby places are not loaded * Add triple checkbox for add none and neutral * Make tri checkbox work * Fix travis issue * Add coments * fix search this area button locaton * Set initial place type state and recover it between each populate places --- .../locations/BookmarkLocationsDao.java | 14 +- .../nrw/commons/nearby/CheckBoxTriStates.java | 195 ++++++++++++++++++ .../fr/free/nrw/commons/nearby/Label.java | 15 +- .../nrw/commons/nearby/MarkerPlaceGroup.java | 31 +++ .../nrw/commons/nearby/NearbyController.java | 33 ++- ...NearbyFilterSearchRecyclerViewAdapter.java | 174 ++++++++++++++++ .../nrw/commons/nearby/NearbyFilterState.java | 57 +++++ .../nearby/NearbyfilterSearchListView.java | 21 ++ .../fr/free/nrw/commons/nearby/Place.java | 19 +- .../nearby/contract/NearbyMapContract.java | 5 + .../NearbyParentFragmentContract.java | 10 + .../nearby/fragments/NearbyMapFragment.java | 142 ++++++++++++- .../fragments/NearbyParentFragment.java | 142 +++++++++++++ .../nearby/model/NearbyResultItem.java | 14 +- .../NearbyParentFragmentPresenter.java | 48 +++++ .../free/nrw/commons/utils/LayoutUtils.java | 60 ++++++ app/src/main/res/color/bg_chip_state.xml | 5 + .../res/drawable/ic_check_box_black_24dp.xml | 9 + .../ic_check_box_outline_blank_black_24dp.xml | 9 + .../drawable/ic_custom_greyed_out_marker.xml | 23 +++ .../drawable/ic_custom_map_marker_green.xml | 23 +++ .../drawable/ic_custom_map_marker_grey.xml | 23 +++ .../ic_indeterminate_check_box_black_24dp.xml | 9 + app/src/main/res/layout/filter_chip_view.xml | 42 ++++ .../res/layout/filter_search_view_layout.xml | 24 +++ .../res/layout/fragment_nearby_parent.xml | 65 +++--- .../res/layout/nearby_filter_all_items.xml | 22 ++ .../main/res/layout/nearby_filter_list.xml | 31 +++ .../res/layout/nearby_search_list_item.xml | 21 ++ app/src/main/res/values-en-rGB/error.xml | 10 - app/src/main/res/values-tcy/strings.xml | 2 +- app/src/main/res/values-tt-cyrl/error.xml | 7 - app/src/main/res/values/strings.xml | 9 +- .../main/resources/queries/nearby_query.rq | 11 +- .../locations/BookMarkLocationDaoTest.kt | 5 +- 35 files changed, 1264 insertions(+), 66 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/CheckBoxTriStates.java create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/MarkerPlaceGroup.java create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/NearbyFilterSearchRecyclerViewAdapter.java create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/NearbyFilterState.java create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/NearbyfilterSearchListView.java create mode 100644 app/src/main/java/fr/free/nrw/commons/utils/LayoutUtils.java create mode 100644 app/src/main/res/color/bg_chip_state.xml create mode 100644 app/src/main/res/drawable/ic_check_box_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_check_box_outline_blank_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_custom_greyed_out_marker.xml create mode 100644 app/src/main/res/drawable/ic_custom_map_marker_green.xml create mode 100644 app/src/main/res/drawable/ic_custom_map_marker_grey.xml create mode 100644 app/src/main/res/drawable/ic_indeterminate_check_box_black_24dp.xml create mode 100644 app/src/main/res/layout/filter_chip_view.xml create mode 100644 app/src/main/res/layout/filter_search_view_layout.xml create mode 100644 app/src/main/res/layout/nearby_filter_all_items.xml create mode 100644 app/src/main/res/layout/nearby_filter_list.xml create mode 100644 app/src/main/res/layout/nearby_search_list_item.xml delete mode 100644 app/src/main/res/values-en-rGB/error.xml delete mode 100644 app/src/main/res/values-tt-cyrl/error.xml diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsDao.java b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsDao.java index a05154e3a..1edff1c07 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsDao.java +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsDao.java @@ -6,6 +6,7 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.RemoteException; import androidx.annotation.NonNull; +import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; import java.util.ArrayList; import java.util.List; @@ -156,8 +157,11 @@ public class BookmarkLocationsDao { cursor.getString(cursor.getColumnIndex(Table.COLUMN_DESCRIPTION)), location, cursor.getString(cursor.getColumnIndex(Table.COLUMN_CATEGORY)), - builder.build() + builder.build(), + null, + null ); + // TODO: add pic and destroyed to bookmark location dao } private ContentValues toContentValues(Place bookmarkLocation) { @@ -172,6 +176,7 @@ public class BookmarkLocationsDao { cv.put(BookmarkLocationsDao.Table.COLUMN_COMMONS_LINK, bookmarkLocation.siteLinks.getCommonsLink().toString()); cv.put(BookmarkLocationsDao.Table.COLUMN_LAT, bookmarkLocation.location.getLatitude()); cv.put(BookmarkLocationsDao.Table.COLUMN_LONG, bookmarkLocation.location.getLongitude()); + cv.put(BookmarkLocationsDao.Table.COLUMN_PIC, bookmarkLocation.pic); return cv; } @@ -189,6 +194,7 @@ public class BookmarkLocationsDao { static final String COLUMN_WIKIPEDIA_LINK = "location_wikipedia_link"; static final String COLUMN_WIKIDATA_LINK = "location_wikidata_link"; static final String COLUMN_COMMONS_LINK = "location_commons_link"; + static final String COLUMN_PIC = "location_pic"; // NOTE! KEEP IN SAME ORDER AS THEY ARE DEFINED UP THERE. HELPS HARD CODE COLUMN INDICES. public static final String[] ALL_FIELDS = { @@ -202,7 +208,8 @@ public class BookmarkLocationsDao { COLUMN_IMAGE_URL, COLUMN_WIKIPEDIA_LINK, COLUMN_WIKIDATA_LINK, - COLUMN_COMMONS_LINK + COLUMN_COMMONS_LINK, + COLUMN_PIC }; static final String DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS " + TABLE_NAME; @@ -218,7 +225,8 @@ public class BookmarkLocationsDao { + COLUMN_IMAGE_URL + " STRING," + COLUMN_WIKIPEDIA_LINK + " STRING," + COLUMN_WIKIDATA_LINK + " STRING," - + COLUMN_COMMONS_LINK + " STRING" + + COLUMN_COMMONS_LINK + " STRING," + + COLUMN_PIC + " STRING" + ");"; public static void onCreate(SQLiteDatabase db) { diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/CheckBoxTriStates.java b/app/src/main/java/fr/free/nrw/commons/nearby/CheckBoxTriStates.java new file mode 100644 index 000000000..d95c1dd16 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/nearby/CheckBoxTriStates.java @@ -0,0 +1,195 @@ +package fr.free.nrw.commons.nearby; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.widget.CompoundButton; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatCheckBox; + +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter; + +/** + * Base on https://stackoverflow.com/a/40939367/3950497 answer. + */ +public class CheckBoxTriStates extends AppCompatCheckBox { + + static public final int UNKNOWN = -1; + + static public final int UNCHECKED = 0; + + static public final int CHECKED = 1; + + private int state; + + /** + * This is the listener set to the super class which is going to be evoke each + * time the check state has changed. + */ + private final OnCheckedChangeListener privateListener = new CompoundButton.OnCheckedChangeListener() { + + // checkbox status is changed from uncheck to checked. + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + switch (state) { + case UNKNOWN: + setState(UNCHECKED);; + break; + case UNCHECKED: + setState(CHECKED); + break; + case CHECKED: + setState(UNKNOWN); + break; + } + } + }; + + /** + * Holds a reference to the listener set by a client, if any. + */ + private OnCheckedChangeListener clientListener; + + /** + * This flag is needed to avoid accidentally changing the current {@link #state} when + * {@link #onRestoreInstanceState(Parcelable)} calls {@link #setChecked(boolean)} + * evoking our {@link #privateListener} and therefore changing the real state. + */ + private boolean restoring; + + public CheckBoxTriStates(Context context) { + super(context); + init(); + } + + public CheckBoxTriStates(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public CheckBoxTriStates(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + public int getState() { + return state; + } + + public void setState(int state) { + if(!this.restoring && this.state != state) { + this.state = state; + + if(this.clientListener != null) { + this.clientListener.onCheckedChanged(this, this.isChecked()); + } + + if (NearbyController.currentLocation != null) { + NearbyParentFragmentPresenter.getInstance().filterByMarkerType(null, state, false, true); + } + updateBtn(); + } + } + + @Override + public void setOnCheckedChangeListener(@Nullable OnCheckedChangeListener listener) { + + // we never truly set the listener to the client implementation, instead we only hold + // a reference to it and evoke it when needed. + if(this.privateListener != listener) { + this.clientListener = listener; + } + + // always use our implementation + super.setOnCheckedChangeListener(privateListener); + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + + SavedState ss = new SavedState(superState); + + ss.state = state; + + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + this.restoring = true; // indicates that the ui is restoring its state + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + setState(ss.state); + requestLayout(); + this.restoring = false; + } + + private void init() { + state = UNKNOWN; + updateBtn(); + } + + public void addAction() { + setOnCheckedChangeListener(this.privateListener); + } + + private void updateBtn() { + int btnDrawable = R.drawable.ic_indeterminate_check_box_black_24dp; + switch (state) { + case UNKNOWN: + btnDrawable = R.drawable.ic_indeterminate_check_box_black_24dp; + break; + case UNCHECKED: + btnDrawable = R.drawable.ic_check_box_outline_blank_black_24dp; + break; + case CHECKED: + btnDrawable = R.drawable.ic_check_box_black_24dp; + break; + } + setButtonDrawable(btnDrawable); + + } + + static class SavedState extends BaseSavedState { + int state; + + SavedState(Parcelable superState) { + super(superState); + } + + private SavedState(Parcel in) { + super(in); + state = in.readInt(); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeValue(state); + } + + @Override + public String toString() { + return "CheckboxTriState.SavedState{" + + Integer.toHexString(System.identityHashCode(this)) + + " state=" + state + "}"; + } + + @SuppressWarnings("hiding") + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/Label.java b/app/src/main/java/fr/free/nrw/commons/nearby/Label.java index 9a36659e8..c97645061 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/Label.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/Label.java @@ -42,7 +42,7 @@ public enum Label { TEMPLE("Q44539", R.drawable.round_icon_church), UNKNOWN("?", R.drawable.round_icon_unknown); - private static final Map TEXT_TO_DESCRIPTION + public static final Map TEXT_TO_DESCRIPTION = new HashMap<>(Label.values().length); static { @@ -54,6 +54,7 @@ public enum Label { private final String text; @DrawableRes private final int icon; + private boolean selected; Label(String text, @DrawableRes int icon) { this.text = text; @@ -65,6 +66,18 @@ public enum Label { this.icon = in.readInt(); } + /** + * Will be used for nearby filter, to determine if place type is selected or not + * @param isSelected true if user selected the place type + */ + public void setSelected(boolean isSelected) { + this.selected = isSelected; + } + + public boolean isSelected() { + return selected; + } + public String getText() { return text; } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/MarkerPlaceGroup.java b/app/src/main/java/fr/free/nrw/commons/nearby/MarkerPlaceGroup.java new file mode 100644 index 000000000..58d63fa6c --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/nearby/MarkerPlaceGroup.java @@ -0,0 +1,31 @@ +package fr.free.nrw.commons.nearby; + +import com.mapbox.mapboxsdk.annotations.Marker; + +/** + * This class groups visual map item Marker with the reated data of displayed place and information + * of bookmark + */ +public class MarkerPlaceGroup { + private Marker marker; // Marker item from the map + private boolean isBookmarked; // True if user bookmarked the place + private Place place; // Place of the location displayed by the marker + + public MarkerPlaceGroup(Marker marker, boolean isBookmarked, Place place) { + this.marker = marker; + this.isBookmarked = isBookmarked; + this.place = place; + } + + public Marker getMarker() { + return marker; + } + + public Place getPlace() { + return place; + } + + public boolean getIsBookmarked() { + return isBookmarked; + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java index 3bd38546a..3477da7f5 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java @@ -6,6 +6,7 @@ import android.graphics.Bitmap; import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; import com.mapbox.mapboxsdk.annotations.IconFactory; +import com.mapbox.mapboxsdk.annotations.Marker; import java.io.IOException; import java.util.ArrayList; @@ -33,6 +34,10 @@ public class NearbyController { public static LatLng latestSearchLocation; // Can be current and camera target on search this area button is used public static double latestSearchRadius = 10.0; // Any last search radius except closest result search + public static List markerLabelList = new ArrayList<>(); + public static Map markerExistsMap; + public static Map markerNeedPicMap; + @Inject public NearbyController(NearbyPlaces nearbyPlaces) { this.nearbyPlaces = nearbyPlaces; @@ -158,6 +163,8 @@ public class NearbyController { placeList = placeList.subList(0, Math.min(placeList.size(), MAX_RESULTS)); VectorDrawableCompat vectorDrawable = null; + VectorDrawableCompat vectorDrawableGreen = null; + VectorDrawableCompat vectorDrawableGrey = null; try { vectorDrawable = VectorDrawableCompat.create( context.getResources(), R.drawable.ic_custom_bookmark_marker, context.getTheme() @@ -191,13 +198,18 @@ public class NearbyController { vectorDrawable = null; try { vectorDrawable = VectorDrawableCompat.create( - context.getResources(), R.drawable.ic_custom_map_marker, context.getTheme() - ); + context.getResources(), R.drawable.ic_custom_map_marker, context.getTheme()); + vectorDrawableGreen = VectorDrawableCompat.create( + context.getResources(), R.drawable.ic_custom_map_marker_green, context.getTheme()); + vectorDrawableGrey = VectorDrawableCompat.create( + context.getResources(), R.drawable.ic_custom_map_marker_grey, context.getTheme()); } catch (Resources.NotFoundException e) { // ignore when running tests. } if (vectorDrawable != null) { Bitmap icon = UiUtils.getBitmap(vectorDrawable); + Bitmap iconGreen = UiUtils.getBitmap(vectorDrawableGreen); + Bitmap iconGrey = UiUtils.getBitmap(vectorDrawableGrey); for (Place place : placeList) { String distance = formatDistanceBetween(curLatLng, place.location); @@ -210,8 +222,21 @@ public class NearbyController { place.location.getLatitude(), place.location.getLongitude())); nearbyBaseMarker.place(place); - nearbyBaseMarker.icon(IconFactory.getInstance(context) - .fromBitmap(icon)); + // Check if string is only spaces or empty, if so place doesn't have any picture + if (!place.pic.trim().isEmpty()) { + if (iconGreen != null) { + nearbyBaseMarker.icon(IconFactory.getInstance(context) + .fromBitmap(iconGreen)); + } + } else if (!place.destroyed.trim().isEmpty()) { // Means place is destroyed + if (iconGrey != null) { + nearbyBaseMarker.icon(IconFactory.getInstance(context) + .fromBitmap(iconGrey)); + } + } else { + nearbyBaseMarker.icon(IconFactory.getInstance(context) + .fromBitmap(icon)); + } baseMarkerOptions.add(nearbyBaseMarker); } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyFilterSearchRecyclerViewAdapter.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyFilterSearchRecyclerViewAdapter.java new file mode 100644 index 000000000..b232f60e2 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyFilterSearchRecyclerViewAdapter.java @@ -0,0 +1,174 @@ +package fr.free.nrw.commons.nearby; + +import android.content.Context; +import android.graphics.Color; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Filter; +import android.widget.Filterable; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; + +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter; + +public class NearbyFilterSearchRecyclerViewAdapter + extends RecyclerView.Adapter + implements Filterable { + + private final LayoutInflater inflater; + private Context context; + private RecyclerView recyclerView; + private ArrayList