mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-31 06:43:56 +01:00 
			
		
		
		
	* Add layout items for nearby filter list and filter item (cherry picked from commitb96f8a68ce) * Edit nearby query (cherry picked from commit1f3c8c8deb) * Add filter items to nearby parent fragment xml (cherry picked from commitd0beadd0e0) * Add icon for green marker (cherry picked from commitf65ca0387a) * Add layout util file to organize layout utilities (cherry picked from commit5c57939245) * Add pic parameter to nearby result item (cherry picked from commit86007e4bb6) * Add pic parameter to place type (cherry picked from commit25c358b67f) * Add green marker styling (cherry picked from commit929c92d887) * Inıt search layouts on Nearby parent (cherry picked from commit2ac38a1919) * Style green markers at nearby controller (cherry picked from commit3e08f39f8e) * Edit bookmark daos to include pic to tables (cherry picked from commit48d69edf3b) * TODO foc bookmark dao item but works now (cherry picked from commitf748399720) * Style nearby filter area (cherry picked from commit6267e488b0) * fix style of filter tab (cherry picked from commit5f843bf366) * Add nearby list adapter (cherry picked from commit56334afe03) * Current status, list size is working, visibility working, filter mechanism is ready (cherry picked from commit7d75c9c589) * Filtering works (cherry picked from commit8a13cf7728) * Filter function works (cherry picked from commit78368a2c0c) * Fix style issues (cherry picked from commit2204f70255) * Add divider to recyclerview (cherry picked from commitc8100b55d7) * Hide bottom sheets accordingly (cherry picked from commitc5deba8b0b) * Code cleanup (cherry picked from commitcf8f64f3cb) * 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
This commit is contained in:
		
							parent
							
								
									5c6ab3b253
								
							
						
					
					
						commit
						b3c11842f3
					
				
					 35 changed files with 1264 additions and 66 deletions
				
			
		|  | @ -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) { | ||||
|  |  | |||
|  | @ -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<SavedState> CREATOR = | ||||
|                 new Parcelable.Creator<SavedState>() { | ||||
|                     @Override | ||||
|                     public SavedState createFromParcel(Parcel in) { | ||||
|                         return new SavedState(in); | ||||
|                     } | ||||
| 
 | ||||
|                     @Override | ||||
|                     public SavedState[] newArray(int size) { | ||||
|                         return new SavedState[size]; | ||||
|                     } | ||||
|                 }; | ||||
|     } | ||||
| } | ||||
|  | @ -42,7 +42,7 @@ public enum Label { | |||
|     TEMPLE("Q44539", R.drawable.round_icon_church), | ||||
|     UNKNOWN("?", R.drawable.round_icon_unknown); | ||||
| 
 | ||||
|     private static final Map<String, Label> TEXT_TO_DESCRIPTION | ||||
|     public static final Map<String, Label> 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; | ||||
|     } | ||||
|  |  | |||
|  | @ -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; | ||||
|     } | ||||
| } | ||||
|  | @ -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<MarkerPlaceGroup> markerLabelList = new ArrayList<>(); | ||||
|     public static Map<Boolean, Marker> markerExistsMap; | ||||
|     public static Map<Boolean, Marker> 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); | ||||
|             } | ||||
|  |  | |||
|  | @ -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<NearbyFilterSearchRecyclerViewAdapter.RecyclerViewHolder> | ||||
|         implements Filterable { | ||||
| 
 | ||||
|     private final LayoutInflater inflater; | ||||
|     private Context context; | ||||
|     private RecyclerView recyclerView; | ||||
|     private ArrayList<Label> labels; | ||||
|     private ArrayList<Label> displayedLabels; | ||||
|     public ArrayList<Label> selectedLabels = new ArrayList<>(); | ||||
| 
 | ||||
|     private int state; | ||||
| 
 | ||||
|     RecyclerView.SmoothScroller smoothScroller; | ||||
| 
 | ||||
|     public NearbyFilterSearchRecyclerViewAdapter(Context context, ArrayList<Label> labels, RecyclerView recyclerView) { | ||||
|         this.context = context; | ||||
|         this.labels = labels; | ||||
|         this.displayedLabels = labels; | ||||
|         this.recyclerView = recyclerView; | ||||
|         smoothScroller = new | ||||
|                 LinearSmoothScroller(context) { | ||||
|                     @Override protected int getVerticalSnapPreference() { | ||||
|                         return LinearSmoothScroller.SNAP_TO_START; | ||||
|                     } | ||||
|                 }; | ||||
|         inflater = LayoutInflater.from(context); | ||||
|     } | ||||
| 
 | ||||
|     public class RecyclerViewHolder extends RecyclerView.ViewHolder { | ||||
|         public TextView placeTypeLabel; | ||||
|         public ImageView placeTypeIcon; | ||||
|         public LinearLayout placeTypeLayout; | ||||
| 
 | ||||
|         public RecyclerViewHolder(View view) { | ||||
|             super(view); | ||||
|             placeTypeLabel = view.findViewById(R.id.place_text); | ||||
|             placeTypeIcon = view.findViewById(R.id.place_icon); | ||||
|             placeTypeLayout = view.findViewById(R.id.search_list_item); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { | ||||
|         View itemView = inflater.inflate(R.layout.nearby_search_list_item, parent, false); | ||||
|         return new RecyclerViewHolder(itemView); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) { | ||||
|         Label label = displayedLabels.get(position); | ||||
|         holder.placeTypeIcon.setImageResource(label.getIcon()); | ||||
|         holder.placeTypeLabel.setText(label.toString()); | ||||
| 
 | ||||
|         holder.placeTypeLayout.setBackgroundColor(label.isSelected() ? ContextCompat.getColor(context, R.color.divider_grey) : Color.WHITE); | ||||
|         holder.placeTypeLayout.setOnClickListener(view -> { | ||||
|             NearbyParentFragmentPresenter.getInstance().setCheckboxUnknown(); | ||||
|             if (label.isSelected()) { | ||||
|                 selectedLabels.remove(label); | ||||
|             } else { | ||||
|                 selectedLabels.add(label); | ||||
|                 displayedLabels.remove(label); | ||||
|                 displayedLabels.add(selectedLabels.size()-1, label); | ||||
|                 notifyDataSetChanged(); | ||||
|                 smoothScroller.setTargetPosition(0); | ||||
|                 recyclerView.getLayoutManager().startSmoothScroll(smoothScroller); | ||||
|             } | ||||
|             label.setSelected(!label.isSelected()); | ||||
|             holder.placeTypeLayout.setBackgroundColor(label.isSelected() ? ContextCompat.getColor(context, R.color.divider_grey) : Color.WHITE); | ||||
|             NearbyParentFragmentPresenter.getInstance().filterByMarkerType(selectedLabels, 0, false, false); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public long getItemId(int position) { | ||||
|         return displayedLabels.get(position).hashCode(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return displayedLabels.size(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Filter getFilter() { | ||||
|         return new Filter() { | ||||
|             @Override | ||||
|             protected FilterResults performFiltering(CharSequence constraint) { | ||||
|                 FilterResults results = new FilterResults(); | ||||
|                 ArrayList<Label> filteredArrayList = new ArrayList<>(); | ||||
| 
 | ||||
|                 if (labels == null) { | ||||
|                     labels = new ArrayList<>(displayedLabels); | ||||
|                 } | ||||
| 
 | ||||
|                 if (constraint == null || constraint.length() == 0) { | ||||
|                     // set the Original result to return | ||||
|                     results.count = labels.size(); | ||||
|                     results.values = labels; | ||||
|                 } else { | ||||
|                     constraint = constraint.toString().toLowerCase(); | ||||
| 
 | ||||
|                     for (Label label : labels) { | ||||
|                         String data = label.toString(); | ||||
|                         if (data.toLowerCase().startsWith(constraint.toString())) { | ||||
|                             filteredArrayList.add(Label.fromText(label.getText())); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     // set the Filtered result to return | ||||
|                     results.count = filteredArrayList.size(); | ||||
|                     results.values = filteredArrayList; | ||||
|                 } | ||||
|                 return results; | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             protected void publishResults(CharSequence constraint, FilterResults results) { | ||||
|                 displayedLabels = (ArrayList<Label>) results.values; // has the filtered values | ||||
|                 notifyDataSetChanged();  // notifies the data with new filtered values | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     public void setRecyclerViewAdapterItemsGreyedOut() { | ||||
|         state = CheckBoxTriStates.UNCHECKED; | ||||
|         for (Label label : labels) { | ||||
|             label.setSelected(false); | ||||
|             selectedLabels.remove(label); | ||||
|         } | ||||
|         notifyDataSetChanged(); | ||||
|     } | ||||
| 
 | ||||
|     public void setRecyclerViewAdapterAllSelected() { | ||||
|         state = CheckBoxTriStates.CHECKED; | ||||
|         for (Label label : labels) { | ||||
|             label.setSelected(true); | ||||
|             if (!selectedLabels.contains(label)) { | ||||
|                 selectedLabels.add(label); | ||||
|             } | ||||
|         } | ||||
|         notifyDataSetChanged(); | ||||
|     } | ||||
| 
 | ||||
|     public void setRecyclerViewAdapterNeutral() { | ||||
|         state = CheckBoxTriStates.UNKNOWN; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,57 @@ | |||
| package fr.free.nrw.commons.nearby; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| public class NearbyFilterState { | ||||
|     private boolean existsSelected; | ||||
|     private boolean needPhotoSelected; | ||||
|     private int checkBoxTriState; | ||||
|     private ArrayList<Label> selectedLabels; | ||||
| 
 | ||||
|     private static NearbyFilterState nearbyFılterStateInstance; | ||||
| 
 | ||||
|     /** | ||||
|      * Define initial filter values here | ||||
|      */ | ||||
|     private NearbyFilterState() { | ||||
|         existsSelected = false; | ||||
|         needPhotoSelected = true; | ||||
|         checkBoxTriState = -1; // Unknown | ||||
|         selectedLabels = new ArrayList<>(); // Initially empty | ||||
|     } | ||||
| 
 | ||||
|     public static NearbyFilterState getInstance() { | ||||
|         if (nearbyFılterStateInstance == null) { | ||||
|             nearbyFılterStateInstance = new NearbyFilterState(); | ||||
|         } | ||||
|         return nearbyFılterStateInstance; | ||||
|     } | ||||
| 
 | ||||
|     public static void setSelectedLabels(ArrayList<Label> selectedLabels) { | ||||
|         getInstance().selectedLabels = selectedLabels; | ||||
|     } | ||||
| 
 | ||||
|     public static void setExistsSelected(boolean existsSelected) { | ||||
|         getInstance().existsSelected = existsSelected; | ||||
|     } | ||||
| 
 | ||||
|     public static void setNeedPhotoSelected(boolean needPhotoSelected) { | ||||
|         getInstance().needPhotoSelected = needPhotoSelected; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isExistsSelected() { | ||||
|         return existsSelected; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isNeedPhotoSelected() { | ||||
|         return needPhotoSelected; | ||||
|     } | ||||
| 
 | ||||
|     public int getCheckBoxTriState() { | ||||
|         return checkBoxTriState; | ||||
|     } | ||||
| 
 | ||||
|     public ArrayList<Label> getSelectedLabels() { | ||||
|         return selectedLabels; | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,21 @@ | |||
| package fr.free.nrw.commons.nearby; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.util.AttributeSet; | ||||
| import android.widget.ListView; | ||||
| 
 | ||||
| public class NearbyfilterSearchListView extends ListView { | ||||
|     public NearbyfilterSearchListView(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
| 
 | ||||
|     public NearbyfilterSearchListView(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|     } | ||||
| 
 | ||||
|     public NearbyfilterSearchListView(Context context, AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -23,18 +23,21 @@ public class Place implements Parcelable { | |||
|     private final String longDescription; | ||||
|     public final LatLng location; | ||||
|     private final String category; | ||||
|     public final String pic; | ||||
|     public final String destroyed; | ||||
| 
 | ||||
|     public String distance; | ||||
|     public final Sitelinks siteLinks; | ||||
| 
 | ||||
| 
 | ||||
|     public Place(String name, Label label, String longDescription, LatLng location, String category, Sitelinks siteLinks) { | ||||
|         this.name = name; | ||||
|     public Place(String name, Label label, String longDescription, LatLng location, String category, Sitelinks siteLinks, String pic, String destroyed) {        this.name = name; | ||||
|         this.label = label; | ||||
|         this.longDescription = longDescription; | ||||
|         this.location = location; | ||||
|         this.category = category; | ||||
|         this.siteLinks = siteLinks; | ||||
|         this.pic = (pic == null) ? "":pic; | ||||
|         this.destroyed = (destroyed == null) ? "":destroyed; | ||||
|     } | ||||
| 
 | ||||
|     public Place(Parcel in) { | ||||
|  | @ -44,6 +47,10 @@ public class Place implements Parcelable { | |||
|         this.location = in.readParcelable(LatLng.class.getClassLoader()); | ||||
|         this.category = in.readString(); | ||||
|         this.siteLinks = in.readParcelable(Sitelinks.class.getClassLoader()); | ||||
|         String picString = in.readString(); | ||||
|         this.pic = (picString == null) ? "":picString; | ||||
|         String destroyedString = in.readString(); | ||||
|         this.destroyed = (destroyedString == null) ? "":destroyedString; | ||||
|     } | ||||
| 
 | ||||
|     public static Place from(NearbyResultItem item) { | ||||
|  | @ -62,7 +69,9 @@ public class Place implements Parcelable { | |||
|                         .setWikipediaLink(item.getWikipediaArticle().getValue()) | ||||
|                         .setCommonsLink(item.getCommonsArticle().getValue()) | ||||
|                         .setWikidataLink(item.getItem().getValue()) | ||||
|                         .build()); | ||||
|                         .build(), | ||||
|                 item.getPic().getValue(), | ||||
|                 item.getDestroyed().getValue()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -105,7 +114,7 @@ public class Place implements Parcelable { | |||
| 
 | ||||
|     /** | ||||
|      * Extracts the entity id from the wikidata link | ||||
|      * @return returns the entity id if wikidata link exists | ||||
|      * @return returns the entity id if wikidata link destroyed | ||||
|      */ | ||||
|     @Nullable | ||||
|     public String getWikiDataEntityId() { | ||||
|  | @ -173,6 +182,8 @@ public class Place implements Parcelable { | |||
|                 ", category='" + category + '\'' + | ||||
|                 ", distance='" + distance + '\'' + | ||||
|                 ", siteLinks='" + siteLinks.toString() + '\'' + | ||||
|                 ", pic='" + pic + '\'' + | ||||
|                 ", destroyed='" + destroyed + '\'' + | ||||
|                 '}'; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; | |||
| import java.util.List; | ||||
| 
 | ||||
| import fr.free.nrw.commons.location.LatLng; | ||||
| import fr.free.nrw.commons.nearby.Label; | ||||
| import fr.free.nrw.commons.nearby.NearbyBaseMarker; | ||||
| import fr.free.nrw.commons.nearby.Place; | ||||
| import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter; | ||||
|  | @ -27,5 +28,9 @@ public interface NearbyMapContract { | |||
|         void addOnCameraMoveListener(MapboxMap.OnCameraMoveListener onCameraMoveListener); | ||||
|         void centerMapToPlace(Place place, boolean isPortraitMode); | ||||
|         void removeCurrentLocationMarker(); | ||||
|         List<NearbyBaseMarker> getBaseMarkerOptions(); | ||||
|         void filterMarkersByLabels(List<Label> labelList, boolean displayExists, boolean displayNeeds, boolean filterForPlaceState, boolean filterForAllNoneType); | ||||
|         void filterOutAllMarkers(); | ||||
|         void displayAllMarkers(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ import java.util.List; | |||
| import fr.free.nrw.commons.kvstore.JsonKvStore; | ||||
| import fr.free.nrw.commons.location.LatLng; | ||||
| import fr.free.nrw.commons.location.LocationServiceManager; | ||||
| import fr.free.nrw.commons.nearby.Label; | ||||
| import fr.free.nrw.commons.nearby.Place; | ||||
| 
 | ||||
| public interface NearbyParentFragmentContract { | ||||
|  | @ -26,6 +27,7 @@ public interface NearbyParentFragmentContract { | |||
|         void animateFABs(); | ||||
|         void recenterMap(LatLng curLatLng); | ||||
|         void hideBottomSheet(); | ||||
|         void hideBottomDetailsSheet(); | ||||
|         void displayBottomSheetWithInfo(Marker marker); | ||||
|         void addOnCameraMoveListener(MapboxMap.OnCameraMoveListener onCameraMoveListener); | ||||
|         void addSearchThisAreaButtonAction(); | ||||
|  | @ -35,6 +37,11 @@ public interface NearbyParentFragmentContract { | |||
|         boolean isDetailsBottomSheetVisible(); | ||||
|         void setBottomSheetDetailsSmaller(); | ||||
|         boolean isSearchThisAreaButtonVisible(); | ||||
|         void setRecyclerViewAdapterAllSelected(); | ||||
|         void setRecyclerViewAdapterItemsGreyedOut(); | ||||
|         void setCheckBoxAction(); | ||||
|         void setCheckBoxState(int state); | ||||
|         void setFilterState(); | ||||
|     } | ||||
| 
 | ||||
|     interface NearbyListView { | ||||
|  | @ -49,6 +56,9 @@ public interface NearbyParentFragmentContract { | |||
|         void setActionListeners(JsonKvStore applicationKvStore); | ||||
|         void backButtonClicked(); | ||||
|         MapboxMap.OnCameraMoveListener onCameraMove(MapboxMap mapboxMap); | ||||
|         void filterByMarkerType(List<Label> selectedLabels, int state, boolean filterForPlaceState, boolean filterForAllNoneType); | ||||
|         void searchViewGainedFocus(); | ||||
|         void setCheckboxUnknown(); | ||||
|     } | ||||
|      | ||||
|     interface ViewsAreReadyCallback { | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; | |||
| import com.mapbox.mapboxsdk.utils.MapFragmentUtils; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
|  | @ -36,6 +37,8 @@ import fr.free.nrw.commons.R; | |||
| import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao; | ||||
| import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; | ||||
| import fr.free.nrw.commons.location.LatLng; | ||||
| import fr.free.nrw.commons.nearby.Label; | ||||
| import fr.free.nrw.commons.nearby.MarkerPlaceGroup; | ||||
| import fr.free.nrw.commons.nearby.NearbyBaseMarker; | ||||
| import fr.free.nrw.commons.nearby.NearbyController; | ||||
| import fr.free.nrw.commons.nearby.NearbyMarker; | ||||
|  | @ -75,6 +78,7 @@ public class NearbyMapFragment extends CommonsDaggerSupportFragment | |||
|     private MapView map; | ||||
|     private Marker currentLocationMarker; | ||||
|     private Polygon currentLocationPolygon; | ||||
|     private List<NearbyBaseMarker> customBaseMarkerOptions; | ||||
| 
 | ||||
|     private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.005; | ||||
|     private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.004; | ||||
|  | @ -273,7 +277,7 @@ public class NearbyMapFragment extends CommonsDaggerSupportFragment | |||
|                                                 , Marker selectedMarker | ||||
|                                                 , NearbyParentFragmentPresenter nearbyParentFragmentPresenter) { | ||||
|         Timber.d("Updates map markers"); | ||||
|         List<NearbyBaseMarker> customBaseMarkerOptions =  NearbyController | ||||
|         customBaseMarkerOptions =  NearbyController | ||||
|                 .loadAttractionsFromLocationToBaseMarkerOptions(latLng, // Curlatlang will be used to calculate distances | ||||
|                         placeList, | ||||
|                         getActivity(), | ||||
|  | @ -336,6 +340,101 @@ public class NearbyMapFragment extends CommonsDaggerSupportFragment | |||
|         mapboxMap.removePolygon(currentLocationPolygon); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Filters markers based on selectedLabels and chips | ||||
|      * @param selectedLabels label list that user clicked | ||||
|      * @param displayExists chip for displaying only existing places | ||||
|      * @param displayNeedsPhoto chip for displaying only places need photos | ||||
|      * @param filterForPlaceState true if we filter places for place state | ||||
|      * @param filterForAllNoneType true if we filter places with all none button | ||||
|      */ | ||||
|     @Override | ||||
|     public void filterMarkersByLabels(List<Label> selectedLabels, | ||||
|                                       boolean displayExists, | ||||
|                                       boolean displayNeedsPhoto, | ||||
|                                       boolean filterForPlaceState, | ||||
|                                       boolean filterForAllNoneType) { | ||||
| 
 | ||||
|         if (selectedLabels.size() == 0 && filterForPlaceState) { // If nothing is selected, display all | ||||
|             greyOutAllMarkers(); | ||||
|             for (MarkerPlaceGroup markerPlaceGroup : NearbyController.markerLabelList) { | ||||
|                 if (displayExists && displayNeedsPhoto) { | ||||
|                     // Exists and needs photo | ||||
|                     if (markerPlaceGroup.getPlace().destroyed.trim().isEmpty() && markerPlaceGroup.getPlace().pic.trim().isEmpty()) { | ||||
|                         updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation); | ||||
|                     } | ||||
|                 } else if (displayExists && !displayNeedsPhoto) { | ||||
|                     // Exists and all included needs and doesn't needs photo | ||||
|                     if (markerPlaceGroup.getPlace().destroyed.trim().isEmpty()) { | ||||
|                         updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation); | ||||
|                     } | ||||
|                 } else if (!displayExists && displayNeedsPhoto) { | ||||
|                     // All and only needs photo | ||||
|                     if (markerPlaceGroup.getPlace().pic.trim().isEmpty()) { | ||||
|                         updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation); | ||||
|                     } | ||||
|                 } else if (!displayExists && !displayNeedsPhoto) { | ||||
|                     // all | ||||
|                     updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation); | ||||
|                 } | ||||
| 
 | ||||
|                 //updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation); | ||||
|             } | ||||
|         } else { | ||||
|             // First greyed out all markers | ||||
|             greyOutAllMarkers(); | ||||
|             for (MarkerPlaceGroup markerPlaceGroup : NearbyController.markerLabelList) { | ||||
|                 for (Label label : selectedLabels) { | ||||
|                     if (markerPlaceGroup.getPlace().getLabel().toString().equals(label.toString())) { | ||||
| 
 | ||||
|                         if (displayExists && displayNeedsPhoto) { | ||||
|                             // Exists and needs photo | ||||
|                             if (markerPlaceGroup.getPlace().destroyed.trim().isEmpty() && markerPlaceGroup.getPlace().pic.trim().isEmpty()) { | ||||
|                                 updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation); | ||||
|                             } | ||||
|                         } else if (displayExists && !displayNeedsPhoto) { | ||||
|                             // Exists and all included needs and doesn't needs photo | ||||
|                             if (markerPlaceGroup.getPlace().destroyed.trim().isEmpty()) { | ||||
|                                 updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation); | ||||
|                             } | ||||
|                         } else if (!displayExists && displayNeedsPhoto) { | ||||
|                             // All and only needs photo | ||||
|                             if (markerPlaceGroup.getPlace().pic.trim().isEmpty()) { | ||||
|                                 updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation); | ||||
|                             } | ||||
|                         } else if (!displayExists && !displayNeedsPhoto) { | ||||
|                             // all | ||||
|                             updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Greys out all markers | ||||
|      */ | ||||
|     @Override | ||||
|     public void filterOutAllMarkers() { | ||||
|         greyOutAllMarkers(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Displays all markers | ||||
|      */ | ||||
|     @Override | ||||
|     public void displayAllMarkers() { | ||||
|         for (MarkerPlaceGroup markerPlaceGroup : NearbyController.markerLabelList) { | ||||
|             updateMarker(markerPlaceGroup.getIsBookmarked(), markerPlaceGroup.getPlace(), NearbyController.currentLocation); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public List<NearbyBaseMarker> getBaseMarkerOptions() { | ||||
|         return customBaseMarkerOptions; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Adds markers to map | ||||
|      * @param baseMarkerList is markers will be added | ||||
|  | @ -346,7 +445,22 @@ public class NearbyMapFragment extends CommonsDaggerSupportFragment | |||
|     public void addNearbyMarkersToMapBoxMap(@Nullable List<NearbyBaseMarker> baseMarkerList | ||||
|                                                         , Marker selectedMarker | ||||
|                                                         , NearbyParentFragmentPresenter nearbyParentFragmentPresenter) { | ||||
|         mapboxMap.addMarkers(baseMarkerList); | ||||
|         List<Marker> markers = mapboxMap.addMarkers(baseMarkerList); | ||||
|         NearbyController.markerExistsMap = new HashMap<Boolean, Marker>(); | ||||
|         NearbyController.markerNeedPicMap = new HashMap<Boolean, Marker>(); | ||||
| 
 | ||||
|         NearbyController.markerLabelList.clear(); | ||||
| 
 | ||||
|         for (int i = 0; i < baseMarkerList.size(); i++) { | ||||
| 
 | ||||
|             NearbyBaseMarker nearbyBaseMarker = baseMarkerList.get(i); | ||||
|             NearbyController.markerLabelList.add( | ||||
|                     new MarkerPlaceGroup(markers.get(i), bookmarkLocationDao.findBookmarkLocation(baseMarkerList.get(i).getPlace()), nearbyBaseMarker.getPlace())); | ||||
|             //TODO: fix bookmark location | ||||
|             NearbyController.markerExistsMap.put((baseMarkerList.get(i).getPlace().hasWikidataLink()), markers.get(i)); | ||||
|             NearbyController.markerNeedPicMap.put(((baseMarkerList.get(i).getPlace().pic == null) ? true : false), markers.get(i)); | ||||
|         } | ||||
| 
 | ||||
|         map.getMapAsync(mapboxMap -> { | ||||
|             mapboxMap.addMarkers(baseMarkerList); | ||||
|             setMapMarkerActions(selectedMarker, nearbyParentFragmentPresenter); | ||||
|  | @ -403,6 +517,14 @@ public class NearbyMapFragment extends CommonsDaggerSupportFragment | |||
|             vectorDrawable = VectorDrawableCompat.create( | ||||
|                     getContext().getResources(), R.drawable.ic_custom_bookmark_marker, getContext().getTheme() | ||||
|             ); | ||||
|         } else if (!place.pic.trim().isEmpty()) { | ||||
|             vectorDrawable = VectorDrawableCompat.create( // Means place has picture | ||||
|                     getContext().getResources(), R.drawable.ic_custom_map_marker_green, getContext().getTheme() | ||||
|             ); | ||||
|         } else if (!place.destroyed.trim().isEmpty()) { // Means place is destroyed | ||||
|             vectorDrawable = VectorDrawableCompat.create( // Means place has picture | ||||
|                     getContext().getResources(), R.drawable.ic_custom_map_marker_grey, getContext().getTheme() | ||||
|             ); | ||||
|         } else { | ||||
|             vectorDrawable = VectorDrawableCompat.create( | ||||
|                     getContext().getResources(), R.drawable.ic_custom_map_marker, getContext().getTheme() | ||||
|  | @ -431,6 +553,22 @@ public class NearbyMapFragment extends CommonsDaggerSupportFragment | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Greys out all markers except current location marker | ||||
|      */ | ||||
|     public void greyOutAllMarkers() { | ||||
|         VectorDrawableCompat vectorDrawable; | ||||
|             vectorDrawable = VectorDrawableCompat.create( | ||||
|                     getContext().getResources(), R.drawable.ic_custom_greyed_out_marker, getContext().getTheme()); | ||||
|         Bitmap icon = UiUtils.getBitmap(vectorDrawable); | ||||
|         for (Marker marker : mapboxMap.getMarkers()) { | ||||
|             if (currentLocationMarker.getTitle() != marker.getTitle()) { | ||||
|                 marker.setIcon(IconFactory.getInstance(getContext()).fromBitmap(icon)); | ||||
|             } | ||||
|         } | ||||
|         addCurrentLocationMarker(NearbyController.currentLocation); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Centers the map in nearby fragment to a given place | ||||
|      * @param place is new center of the map | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ import android.content.Intent; | |||
| import android.content.IntentFilter; | ||||
| import android.content.res.Configuration; | ||||
| import android.os.Bundle; | ||||
| import android.util.Log; | ||||
| import android.view.Gravity; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
|  | @ -19,6 +20,7 @@ import android.widget.FrameLayout; | |||
| import android.widget.ImageView; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.ProgressBar; | ||||
| import android.widget.SearchView; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| 
 | ||||
|  | @ -26,10 +28,17 @@ import androidx.annotation.NonNull; | |||
| import androidx.constraintlayout.widget.ConstraintLayout; | ||||
| import androidx.fragment.app.FragmentManager; | ||||
| import androidx.fragment.app.FragmentTransaction; | ||||
| import androidx.recyclerview.widget.DividerItemDecoration; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import com.google.android.material.bottomsheet.BottomSheetBehavior; | ||||
| import com.google.android.material.chip.Chip; | ||||
| import com.google.android.material.chip.ChipGroup; | ||||
| import com.google.android.material.floatingactionbutton.FloatingActionButton; | ||||
| import com.google.android.material.snackbar.Snackbar; | ||||
| import com.jakewharton.rxbinding2.view.RxView; | ||||
| import com.jakewharton.rxbinding2.widget.RxSearchView; | ||||
| import com.mapbox.mapboxsdk.Mapbox; | ||||
| import com.mapbox.mapboxsdk.annotations.Marker; | ||||
| import com.mapbox.mapboxsdk.camera.CameraPosition; | ||||
|  | @ -39,6 +48,9 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; | |||
| import com.mapbox.mapboxsdk.maps.MapboxMapOptions; | ||||
| import com.mapbox.mapboxsdk.maps.Style; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| import javax.inject.Named; | ||||
| 
 | ||||
|  | @ -54,12 +66,16 @@ import fr.free.nrw.commons.contributions.MainActivity; | |||
| import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; | ||||
| import fr.free.nrw.commons.kvstore.JsonKvStore; | ||||
| import fr.free.nrw.commons.location.LocationServiceManager; | ||||
| import fr.free.nrw.commons.nearby.CheckBoxTriStates; | ||||
| import fr.free.nrw.commons.nearby.NearbyController; | ||||
| import fr.free.nrw.commons.nearby.NearbyFilterSearchRecyclerViewAdapter; | ||||
| import fr.free.nrw.commons.nearby.NearbyFilterState; | ||||
| import fr.free.nrw.commons.nearby.NearbyMarker; | ||||
| import fr.free.nrw.commons.nearby.Place; | ||||
| import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract; | ||||
| import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter; | ||||
| import fr.free.nrw.commons.utils.FragmentUtils; | ||||
| import fr.free.nrw.commons.utils.LayoutUtils; | ||||
| import fr.free.nrw.commons.utils.NearbyFABUtils; | ||||
| import fr.free.nrw.commons.utils.NetworkUtils; | ||||
| import fr.free.nrw.commons.utils.PermissionUtils; | ||||
|  | @ -73,6 +89,7 @@ import timber.log.Timber; | |||
| import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED; | ||||
| import static fr.free.nrw.commons.contributions.MainActivity.CONTRIBUTIONS_TAB_POSITION; | ||||
| import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED; | ||||
| import static fr.free.nrw.commons.nearby.Label.TEXT_TO_DESCRIPTION; | ||||
| import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT; | ||||
| 
 | ||||
| 
 | ||||
|  | @ -106,6 +123,14 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment | |||
|     @BindView(R.id.container_sheet) FrameLayout frameLayout; | ||||
|     @BindView(R.id.loading_nearby_list) ConstraintLayout loadingNearbyLayout; | ||||
| 
 | ||||
|     @BindView(R.id.choice_chip_exists) Chip chipExists; | ||||
|     @BindView(R.id.choice_chip_needs_photo) Chip chipNeedsPhoto; | ||||
|     @BindView(R.id.choice_chip_group) ChipGroup choiceChipGroup; | ||||
|     @BindView(R.id.search_view) SearchView searchView; | ||||
|     @BindView(R.id.search_list_view) RecyclerView recyclerView; | ||||
|     @BindView(R.id.nearby_filter_list) View nearbyFilterList; | ||||
|     @BindView(R.id.checkbox_tri_states) CheckBoxTriStates checkBoxTriStates; | ||||
| 
 | ||||
|     @Inject LocationServiceManager locationManager; | ||||
|     @Inject NearbyController nearbyController; | ||||
|     @Inject @Named("default_preferences") JsonKvStore applicationKvStore; | ||||
|  | @ -113,6 +138,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment | |||
|     @Inject ContributionController controller; | ||||
|     @Inject WikidataEditListener wikidataEditListener; | ||||
| 
 | ||||
|     private NearbyFilterSearchRecyclerViewAdapter nearbyFilterSearchRecyclerViewAdapter; | ||||
| 
 | ||||
|     private BottomSheetBehavior bottomSheetListBehavior; | ||||
|     private BottomSheetBehavior bottomSheetDetailsBehavior; | ||||
|     private Animation rotate_backward; | ||||
|  | @ -178,6 +205,98 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment | |||
|         bottomSheetDetails.setVisibility(View.VISIBLE); | ||||
|     } | ||||
| 
 | ||||
|     public void initNearbyFilter() { | ||||
|         nearbyFilterList.setVisibility(View.GONE); | ||||
| 
 | ||||
|         searchView.setOnQueryTextFocusChangeListener((v, hasFocus) -> { | ||||
|             if (hasFocus) { | ||||
|                 nearbyParentFragmentPresenter.searchViewGainedFocus(); | ||||
|                 nearbyFilterList.setVisibility(View.VISIBLE); | ||||
|             } else { | ||||
|                 nearbyFilterList.setVisibility(View.GONE); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         recyclerView.setHasFixedSize(true); | ||||
|         recyclerView.addItemDecoration(new DividerItemDecoration(getContext(), | ||||
|                 DividerItemDecoration.VERTICAL)); | ||||
| 
 | ||||
|         LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); | ||||
|         linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); | ||||
|         recyclerView.setLayoutManager(linearLayoutManager); | ||||
| 
 | ||||
|         nearbyFilterSearchRecyclerViewAdapter = new NearbyFilterSearchRecyclerViewAdapter(getContext(),new ArrayList<>(TEXT_TO_DESCRIPTION.values()), recyclerView); | ||||
|         nearbyFilterList.getLayoutParams().width = (int) LayoutUtils.getScreenWidth(getActivity(), 0.75); | ||||
|         recyclerView.setAdapter(nearbyFilterSearchRecyclerViewAdapter); | ||||
|         LayoutUtils.setLayoutHeightAllignedToWidth(1, nearbyFilterList); | ||||
| 
 | ||||
|         compositeDisposable.add(RxSearchView.queryTextChanges(searchView) | ||||
|                 .takeUntil(RxView.detaches(searchView)) | ||||
|                 .debounce(500, TimeUnit.MILLISECONDS) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe( query -> { | ||||
|                     ((NearbyFilterSearchRecyclerViewAdapter) recyclerView.getAdapter()).getFilter().filter(query.toString()); | ||||
|                 })); | ||||
|         initFilterChips(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setCheckBoxAction() { | ||||
|         checkBoxTriStates.addAction(); | ||||
|         checkBoxTriStates.setState(CheckBoxTriStates.UNKNOWN); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setCheckBoxState(int state) { | ||||
|         checkBoxTriStates.setState(state); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setFilterState() { | ||||
|         Log.d("deneme5","setfilterState"); | ||||
|         chipNeedsPhoto.setChecked(NearbyFilterState.getInstance().isNeedPhotoSelected()); | ||||
|         chipExists.setChecked(NearbyFilterState.getInstance().isExistsSelected()); | ||||
| 
 | ||||
|         if (NearbyController.currentLocation != null) { | ||||
|             NearbyParentFragmentPresenter.getInstance().filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private void initFilterChips() { | ||||
| 
 | ||||
|         chipNeedsPhoto.setOnCheckedChangeListener((buttonView, isChecked) -> { | ||||
|             if (NearbyController.currentLocation != null) { | ||||
|                 checkBoxTriStates.setState(CheckBoxTriStates.UNKNOWN); | ||||
|                 if (isChecked) { | ||||
|                     NearbyFilterState.getInstance().setNeedPhotoSelected(true); | ||||
|                     NearbyParentFragmentPresenter.getInstance().filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false); | ||||
|                 } else { | ||||
|                     NearbyFilterState.getInstance().setNeedPhotoSelected(false); | ||||
|                     NearbyParentFragmentPresenter.getInstance().filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false); | ||||
|                 } | ||||
|             } else { | ||||
|                 chipNeedsPhoto.setChecked(!isChecked); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
| 
 | ||||
|         chipExists.setOnCheckedChangeListener((buttonView, isChecked) -> { | ||||
|             if (NearbyController.currentLocation != null) { | ||||
|                 checkBoxTriStates.setState(CheckBoxTriStates.UNKNOWN); | ||||
|                 if (isChecked) { | ||||
|                     NearbyFilterState.getInstance().setExistsSelected(true); | ||||
|                     NearbyParentFragmentPresenter.getInstance().filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false); | ||||
|                 } else { | ||||
|                     NearbyFilterState.getInstance().setExistsSelected(false); | ||||
|                     NearbyParentFragmentPresenter.getInstance().filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false); | ||||
|                 } | ||||
|             } else { | ||||
|                 chipExists.setChecked(!isChecked); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Defines how bottom sheets will act on click | ||||
|      */ | ||||
|  | @ -385,6 +504,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment | |||
|         nearbyParentFragmentPresenter.nearbyFragmentsAreReady(); | ||||
|         initViews(); | ||||
|         nearbyParentFragmentPresenter.setActionListeners(applicationKvStore); | ||||
|         initNearbyFilter(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  | @ -483,6 +603,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment | |||
|                             // showErrorMessage(getString(R.string.error_fetching_nearby_places)); | ||||
|                             setProgressBarVisibility(false); | ||||
|                             nearbyParentFragmentPresenter.lockUnlockNearby(false); | ||||
|                             setFilterState(); | ||||
|                         })); | ||||
|     } | ||||
| 
 | ||||
|  | @ -509,6 +630,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment | |||
|      */ | ||||
|     private void updateMapMarkers(NearbyController.NearbyPlacesInfo nearbyPlacesInfo) { | ||||
|         nearbyParentFragmentPresenter.updateMapMarkers(nearbyPlacesInfo, selectedMarker); | ||||
|         setFilterState(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -518,6 +640,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment | |||
|      */ | ||||
|     private void updateMapMarkersForCustomLocation(NearbyController.NearbyPlacesInfo nearbyPlacesInfo) { | ||||
|         nearbyParentFragmentPresenter.updateMapMarkersForCustomLocation(nearbyPlacesInfo, selectedMarker); | ||||
|         setFilterState(); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -563,6 +686,20 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setRecyclerViewAdapterAllSelected() { | ||||
|         if (nearbyFilterSearchRecyclerViewAdapter != null && NearbyController.currentLocation != null) { | ||||
|             nearbyFilterSearchRecyclerViewAdapter.setRecyclerViewAdapterAllSelected(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setRecyclerViewAdapterItemsGreyedOut() { | ||||
|         if (nearbyFilterSearchRecyclerViewAdapter != null && NearbyController.currentLocation != null) { | ||||
|             nearbyFilterSearchRecyclerViewAdapter.setRecyclerViewAdapterItemsGreyedOut(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setProgressBarVisibility(boolean isVisible) { | ||||
|         if (isVisible) { | ||||
|  | @ -729,6 +866,11 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment | |||
|         bottomSheetListBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void hideBottomDetailsSheet() { | ||||
|         bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void displayBottomSheetWithInfo(Marker marker) { | ||||
|         this.selectedMarker = marker; | ||||
|  |  | |||
|  | @ -12,6 +12,8 @@ public class NearbyResultItem { | |||
|     @SerializedName("class") private final ResultTuple className; | ||||
|     @SerializedName("classLabel") private final ResultTuple classLabel; | ||||
|     @SerializedName("commonsCategory") private final ResultTuple commonsCategory; | ||||
|     @SerializedName("pic") private final ResultTuple pic; | ||||
|     @SerializedName("destroyed") private final ResultTuple destroyed; | ||||
| 
 | ||||
|     public NearbyResultItem(ResultTuple item, | ||||
|                             ResultTuple wikipediaArticle, | ||||
|  | @ -20,7 +22,9 @@ public class NearbyResultItem { | |||
|                             ResultTuple label, | ||||
|                             ResultTuple icon, ResultTuple className, | ||||
|                             ResultTuple classLabel, | ||||
|                             ResultTuple commonsCategory) { | ||||
|                             ResultTuple commonsCategory, | ||||
|                             ResultTuple pic, | ||||
|                             ResultTuple destroyed) { | ||||
|         this.item = item; | ||||
|         this.wikipediaArticle = wikipediaArticle; | ||||
|         this.commonsArticle = commonsArticle; | ||||
|  | @ -30,6 +34,8 @@ public class NearbyResultItem { | |||
|         this.className = className; | ||||
|         this.classLabel = classLabel; | ||||
|         this.commonsCategory = commonsCategory; | ||||
|         this.pic = pic; | ||||
|         this.destroyed = destroyed; | ||||
|     } | ||||
| 
 | ||||
|     public ResultTuple getItem() { | ||||
|  | @ -67,4 +73,10 @@ public class NearbyResultItem { | |||
|     public ResultTuple getCommonsCategory() { | ||||
|         return commonsCategory == null ? new ResultTuple():commonsCategory; | ||||
|     } | ||||
|     public ResultTuple getPic() { | ||||
|         return pic == null ? new ResultTuple():pic; | ||||
|     } | ||||
|     public ResultTuple getDestroyed() { | ||||
|         return destroyed == null ? new ResultTuple(): destroyed; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -5,11 +5,16 @@ import android.view.View; | |||
| import com.mapbox.mapboxsdk.annotations.Marker; | ||||
| import com.mapbox.mapboxsdk.maps.MapboxMap; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| import fr.free.nrw.commons.kvstore.JsonKvStore; | ||||
| import fr.free.nrw.commons.location.LatLng; | ||||
| import fr.free.nrw.commons.location.LocationServiceManager; | ||||
| import fr.free.nrw.commons.location.LocationUpdateListener; | ||||
| import fr.free.nrw.commons.nearby.CheckBoxTriStates; | ||||
| import fr.free.nrw.commons.nearby.Label; | ||||
| import fr.free.nrw.commons.nearby.NearbyController; | ||||
| import fr.free.nrw.commons.nearby.NearbyFilterState; | ||||
| import fr.free.nrw.commons.nearby.Place; | ||||
| import fr.free.nrw.commons.nearby.contract.NearbyMapContract; | ||||
| import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract; | ||||
|  | @ -22,6 +27,9 @@ import static fr.free.nrw.commons.location.LocationServiceManager.LocationChange | |||
| import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED; | ||||
| import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED; | ||||
| import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.SEARCH_CUSTOM_AREA; | ||||
| import static fr.free.nrw.commons.nearby.CheckBoxTriStates.CHECKED; | ||||
| import static fr.free.nrw.commons.nearby.CheckBoxTriStates.UNCHECKED; | ||||
| import static fr.free.nrw.commons.nearby.CheckBoxTriStates.UNKNOWN; | ||||
| 
 | ||||
| public class NearbyParentFragmentPresenter | ||||
|         implements NearbyParentFragmentContract.UserActions, | ||||
|  | @ -135,6 +143,7 @@ public class NearbyParentFragmentPresenter | |||
|         updateMapAndList(LOCATION_SIGNIFICANTLY_CHANGED, null); | ||||
|         this.nearbyParentFragmentView.addSearchThisAreaButtonAction(); | ||||
|         this.nearbyMapFragmentView.addOnCameraMoveListener(onCameraMove(getMapboxMap())); | ||||
|         nearbyParentFragmentView.setCheckBoxAction(); | ||||
|         mapInitialized = true; | ||||
|     } | ||||
| 
 | ||||
|  | @ -345,6 +354,45 @@ public class NearbyParentFragmentPresenter | |||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void filterByMarkerType(List<Label> selectedLabels, int state, boolean filterForPlaceState, boolean filterForAllNoneType) { | ||||
|         if (filterForAllNoneType) { // Means we will set labels based on states | ||||
|             switch (state) { | ||||
|                 case UNKNOWN: | ||||
|                     // Do nothing | ||||
|                     break; | ||||
|                 case UNCHECKED: | ||||
|                     nearbyMapFragmentView.filterOutAllMarkers(); | ||||
|                     nearbyParentFragmentView.setRecyclerViewAdapterItemsGreyedOut(); | ||||
|                     break; | ||||
|                 case CHECKED: | ||||
|                     nearbyMapFragmentView.displayAllMarkers(); | ||||
|                     nearbyParentFragmentView.setRecyclerViewAdapterAllSelected(); | ||||
|                     break; | ||||
|             } | ||||
|         } else { | ||||
|             nearbyMapFragmentView.filterMarkersByLabels(selectedLabels, | ||||
|                     NearbyFilterState.getInstance().isExistsSelected(), | ||||
|                     NearbyFilterState.getInstance().isNeedPhotoSelected(), | ||||
|                     filterForPlaceState, filterForAllNoneType); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setCheckboxUnknown() { | ||||
|         nearbyParentFragmentView.setCheckBoxState(CheckBoxTriStates.UNKNOWN); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void searchViewGainedFocus() { | ||||
|         if(nearbyParentFragmentView.isListBottomSheetExpanded()) { | ||||
|             // Back should first hide the bottom sheet if it is expanded | ||||
|             nearbyParentFragmentView.hideBottomSheet(); | ||||
|         } else if (nearbyParentFragmentView.isDetailsBottomSheetVisible()) { | ||||
|             nearbyParentFragmentView.hideBottomDetailsSheet(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public View.OnClickListener onSearchThisAreaClicked() { | ||||
|         return v -> { | ||||
|             // Lock map operations during search this area operation | ||||
|  |  | |||
							
								
								
									
										60
									
								
								app/src/main/java/fr/free/nrw/commons/utils/LayoutUtils.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								app/src/main/java/fr/free/nrw/commons/utils/LayoutUtils.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| package fr.free.nrw.commons.utils; | ||||
| 
 | ||||
| import android.app.Activity; | ||||
| import android.content.Context; | ||||
| import android.util.DisplayMetrics; | ||||
| import android.util.Log; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.view.ViewTreeObserver; | ||||
| 
 | ||||
| public class LayoutUtils { | ||||
| 
 | ||||
|     /** | ||||
|      * Can be used for keeping aspect radios suggested by material guidelines. See: | ||||
|      * https://material.io/design/layout/spacing-methods.html#containers-aspect-ratios | ||||
|      * In some cases we don't know exact width, for such cases this method measures | ||||
|      * width and sets height by multiplying the width with height. | ||||
|      * @param rate Aspect ratios, ie 1 for 1:1. (width * rate = height) | ||||
|      * @param view view to change height | ||||
|      */ | ||||
|     public static void setLayoutHeightAllignedToWidth(double rate, View view) { | ||||
|         ViewTreeObserver vto = view.getViewTreeObserver(); | ||||
|         vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { | ||||
|             @Override | ||||
|             public void onGlobalLayout() { | ||||
|                 view.getViewTreeObserver().removeOnGlobalLayoutListener(this); | ||||
|                 ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); | ||||
|                 layoutParams.height = (int) (view.getWidth() * rate); | ||||
|                 view.setLayoutParams(layoutParams); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Can be used for keeping aspect radios suggested by material guidelines. See: | ||||
|      * https://material.io/design/layout/spacing-methods.html#containers-aspect-ratios | ||||
|      * In some cases we don't know exact height, for such cases this method measures | ||||
|      * height and sets width by multiplying the width with height. | ||||
|      * @param rate Aspect ratios, ie 1 for 1:1. (height * rate = width) | ||||
|      * @param view view to change width | ||||
|      */ | ||||
|     public static void setLayoutWidthAllignedToHeight(double rate, View view) { | ||||
|         ViewTreeObserver vto = view.getViewTreeObserver(); | ||||
|         vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { | ||||
|             @Override | ||||
|             public void onGlobalLayout() { | ||||
|                 view.getViewTreeObserver().removeOnGlobalLayoutListener(this); | ||||
|                 ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); | ||||
|                 layoutParams.width = (int) (view.getHeight() * rate); | ||||
|                 view.setLayoutParams(layoutParams); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public static double getScreenWidth(Context context, double rate) { | ||||
|         DisplayMetrics displayMetrics = new DisplayMetrics(); | ||||
|         ((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); | ||||
|         return displayMetrics.widthPixels * rate; | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 neslihanturan
						neslihanturan