package net.osmand.plus.search;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import net.osmand.binary.BinaryMapIndexReader.SearchPoiTypeFilter;
import net.osmand.data.Amenity;
import net.osmand.data.City;
import net.osmand.data.FavouritePoint;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.data.QuadRect;
import net.osmand.data.Street;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
import net.osmand.plus.GPXUtilities;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.OsmAndListFragment;
import net.osmand.plus.dashboard.DashLocationFragment;
import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry;
import net.osmand.plus.search.listitems.QuickSearchBottomShadowListItem;
import net.osmand.plus.search.listitems.QuickSearchButtonListItem;
import net.osmand.plus.search.listitems.QuickSearchListItem;
import net.osmand.plus.search.listitems.QuickSearchListItemType;
import net.osmand.plus.search.listitems.QuickSearchMoreListItem;
import net.osmand.plus.search.listitems.QuickSearchTopShadowListItem;
import net.osmand.search.core.ObjectType;
import net.osmand.search.core.SearchResult;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import java.util.ArrayList;
import java.util.List;
public abstract class QuickSearchListFragment extends OsmAndListFragment {
private QuickSearchDialogFragment dialogFragment;
private QuickSearchListAdapter listAdapter;
private boolean touching;
private boolean scrolling;
enum SearchListFragmentType {
HISTORY,
CATEGORIES,
ADDRESS,
MAIN
}
public abstract SearchListFragmentType getType();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.search_dialog_list_layout, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ListView listView = getListView();
if (listView != null) {
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
scrolling = (scrollState != AbsListView.OnScrollListener.SCROLL_STATE_IDLE);
if (scrolling) {
dialogFragment.hideKeyboard();
}
}
});
}
}
@Override
public void onListItemClick(ListView l, View view, int position, long id) {
int index = position - l.getHeaderViewsCount();
if (index < listAdapter.getCount()) {
QuickSearchListItem item = listAdapter.getItem(index);
if (item != null) {
if (item.getType() == QuickSearchListItemType.SEARCH_MORE) {
((QuickSearchMoreListItem) item).getOnClickListener().onClick(view);
} else if (item.getType() == QuickSearchListItemType.BUTTON) {
((QuickSearchButtonListItem) item).getOnClickListener().onClick(view);
} else if (item.getType() == QuickSearchListItemType.SEARCH_RESULT) {
SearchResult sr = item.getSearchResult();
if (sr.objectType == ObjectType.POI
|| sr.objectType == ObjectType.LOCATION
|| sr.objectType == ObjectType.HOUSE
|| sr.objectType == ObjectType.FAVORITE
|| sr.objectType == ObjectType.RECENT_OBJ
|| sr.objectType == ObjectType.WPT
|| sr.objectType == ObjectType.STREET_INTERSECTION) {
showResult(sr);
} else {
dialogFragment.completeQueryWithObject(item.getSearchResult());
}
}
}
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
dialogFragment = (QuickSearchDialogFragment) getParentFragment();
listAdapter = new QuickSearchListAdapter(getMyApplication(), getActivity());
listAdapter.setAccessibilityAssistant(dialogFragment.getAccessibilityAssistant());
listAdapter.setUseMapCenter(dialogFragment.isUseMapCenter());
setListAdapter(listAdapter);
ListView listView = getListView();
listView.setBackgroundColor(getResources().getColor(
getMyApplication().getSettings().isLightContent() ? R.color.ctx_menu_info_view_bg_light
: R.color.ctx_menu_info_view_bg_dark));
listView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
touching = true;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
touching = false;
break;
}
return false;
}
});
}
@Override
public QuickSearchListAdapter getListAdapter() {
return listAdapter;
}
public ArrayAdapter<?> getAdapter() {
return listAdapter;
}
public QuickSearchDialogFragment getDialogFragment() {
return dialogFragment;
}
@Override
public void onResume() {
super.onResume();
int screenOrientation = DashLocationFragment.getScreenOrientation(getActivity());
listAdapter.setScreenOrientation(screenOrientation);
dialogFragment.onSearchListFragmentResume(this);
}
public void showResult(SearchResult searchResult) {
if (searchResult.location != null) {
OsmandApplication app = getMyApplication();
String lang = searchResult.requiredSearchPhrase.getSettings().getLang();
boolean transliterate = searchResult.requiredSearchPhrase.getSettings().isTransliterate();
PointDescription pointDescription = null;
Object object = searchResult.object;
switch (searchResult.objectType) {
case POI:
Amenity a = (Amenity) object;
String poiSimpleFormat = OsmAndFormatter.getPoiStringWithoutType(a, lang, transliterate);
pointDescription = new PointDescription(PointDescription.POINT_TYPE_POI, poiSimpleFormat);
pointDescription.setIconName(QuickSearchListItem.getAmenityIconName(a));
break;
case RECENT_OBJ:
HistoryEntry entry = (HistoryEntry) object;
pointDescription = entry.getName();
if (pointDescription.isPoi()) {
Amenity amenity = findAmenity(entry.getName().getName(), entry.getLat(), entry.getLon(), lang, transliterate);
if (amenity != null) {
object = amenity;
pointDescription = new PointDescription(PointDescription.POINT_TYPE_POI,
OsmAndFormatter.getPoiStringWithoutType(amenity, lang, transliterate));
pointDescription.setIconName(QuickSearchListItem.getAmenityIconName(amenity));
}
} else if (pointDescription.isFavorite()) {
LatLon entryLatLon = new LatLon(entry.getLat(), entry.getLon());
List<FavouritePoint> favs = app.getFavorites().getFavouritePoints();
for (FavouritePoint f : favs) {
if (entryLatLon.equals(new LatLon(f.getLatitude(), f.getLongitude()))
&& pointDescription.getName().equals(f.getName())) {
object = f;
pointDescription = f.getPointDescription();
break;
}
}
}
break;
case FAVORITE:
FavouritePoint fav = (FavouritePoint) object;
pointDescription = fav.getPointDescription();
break;
case CITY:
String cityName = searchResult.localeName;
String typeNameCity = QuickSearchListItem.getTypeName(app, searchResult);
pointDescription = new PointDescription(PointDescription.POINT_TYPE_ADDRESS, typeNameCity, cityName);
pointDescription.setIconName("ic_action_building_number");
break;
case STREET:
String streetName = searchResult.localeName;
String typeNameStreet = QuickSearchListItem.getTypeName(app, searchResult);
pointDescription = new PointDescription(PointDescription.POINT_TYPE_ADDRESS, typeNameStreet, streetName);
pointDescription.setIconName("ic_action_street_name");
break;
case HOUSE:
String typeNameHouse = null;
String name = searchResult.localeName;
if (searchResult.relatedObject instanceof City) {
name = ((City) searchResult.relatedObject).getName(searchResult.requiredSearchPhrase.getSettings().getLang(), true) + " " + name;
} else if (searchResult.relatedObject instanceof Street) {
String s = ((Street) searchResult.relatedObject).getName(searchResult.requiredSearchPhrase.getSettings().getLang(), true);
typeNameHouse = ((Street) searchResult.relatedObject).getCity().getName(searchResult.requiredSearchPhrase.getSettings().getLang(), true);
name = s + " " + name;
} else if (searchResult.localeRelatedObjectName != null) {
name = searchResult.localeRelatedObjectName + " " + name;
}
pointDescription = new PointDescription(PointDescription.POINT_TYPE_ADDRESS, typeNameHouse, name);
pointDescription.setIconName("ic_action_building");
break;
case LOCATION:
pointDescription = new PointDescription(
searchResult.location.getLatitude(), searchResult.location.getLongitude());
pointDescription.setIconName("ic_action_world_globe");
break;
case STREET_INTERSECTION:
String typeNameIntersection = QuickSearchListItem.getTypeName(app, searchResult);
if (Algorithms.isEmpty(typeNameIntersection)) {
typeNameIntersection = null;
}
pointDescription = new PointDescription(PointDescription.POINT_TYPE_ADDRESS,
typeNameIntersection, QuickSearchListItem.getName(app, searchResult));
pointDescription.setIconName("ic_action_intersection");
break;
case WPT:
GPXUtilities.WptPt wpt = (GPXUtilities.WptPt) object;
pointDescription = wpt.getPointDescription(getMyApplication());
break;
}
dialogFragment.hideToolbar();
dialogFragment.hide();
showOnMap(getMapActivity(), dialogFragment,
searchResult.location.getLatitude(), searchResult.location.getLongitude(),
searchResult.preferredZoom, pointDescription, object);
}
}
public static void showOnMap(MapActivity mapActivity, QuickSearchDialogFragment dialogFragment,
double latitude, double longitude, int zoom,
PointDescription pointDescription, Object object) {
if (mapActivity != null) {
OsmandApplication app = mapActivity.getMyApplication();
switch (dialogFragment.getSearchType()) {
case REGULAR: {
app.getSettings().setMapLocationToShow(latitude, longitude, zoom, pointDescription, true, object);
MapActivity.launchMapActivityMoveToTop(mapActivity);
dialogFragment.reloadHistory();
break;
}
case START_POINT: {
mapActivity.getMapLayers().getMapControlsLayer().selectAddress(
pointDescription != null ? pointDescription.getName() : null,
latitude, longitude, false);
break;
}
case DESTINATION: {
mapActivity.getMapLayers().getMapControlsLayer().selectAddress(
pointDescription != null ? pointDescription.getName() : null,
latitude, longitude, true);
break;
}
}
}
}
private Amenity findAmenity(String name, double lat, double lon, String lang, boolean transliterate) {
OsmandApplication app = getMyApplication();
QuadRect rect = MapUtils.calculateLatLonBbox(lat, lon, 15);
List<Amenity> amenities = app.getResourceManager().searchAmenities(
new SearchPoiTypeFilter() {
@Override
public boolean accept(PoiCategory type, String subcategory) {
return true;
}
@Override
public boolean isEmpty() {
return false;
}
}, rect.top, rect.left, rect.bottom, rect.right, -1, null);
MapPoiTypes types = app.getPoiTypes();
for (Amenity amenity : amenities) {
String poiSimpleFormat = OsmAndFormatter.getPoiStringWithoutType(amenity, lang, transliterate);
if (poiSimpleFormat.equals(name)) {
return amenity;
}
}
for (Amenity amenity : amenities) {
String amenityName = amenity.getName(lang, transliterate);
if (Algorithms.isEmpty(amenityName)) {
AbstractPoiType st = types.getAnyPoiTypeByKey(amenity.getSubType());
if (st != null) {
amenityName = st.getTranslation();
} else {
amenityName = amenity.getSubType();
}
}
if (name.contains(amenityName)) {
return amenity;
}
}
return null;
}
public MapActivity getMapActivity() {
return (MapActivity) getActivity();
}
public void updateLocation(LatLon latLon, Float heading) {
if (listAdapter != null && !touching && !scrolling) {
listAdapter.setLocation(latLon);
listAdapter.setHeading(heading);
dialogFragment.getAccessibilityAssistant().lockEvents();
listAdapter.notifyDataSetChanged();
dialogFragment.getAccessibilityAssistant().unlockEvents();
final View selected = dialogFragment.getAccessibilityAssistant().getFocusedView();
if (selected != null) {
try {
int position = getListView().getPositionForView(selected);
if ((position != AdapterView.INVALID_POSITION) && (position >= getListView().getHeaderViewsCount())) {
dialogFragment.getNavigationInfo().updateTargetDirection(listAdapter.getItem(position - getListView().getHeaderViewsCount()).getSearchResult().location, heading.floatValue());
}
} catch (Exception e) {
return;
}
}
}
}
public void updateListAdapter(List<QuickSearchListItem> listItems, boolean append) {
if (listAdapter != null) {
List<QuickSearchListItem> list = new ArrayList<>(listItems);
if (list.size() > 0) {
list.add(0, new QuickSearchTopShadowListItem(getMyApplication()));
list.add(new QuickSearchBottomShadowListItem(getMyApplication()));
}
listAdapter.setListItems(list);
if (!append) {
getListView().setSelection(0);
}
}
}
public void addListItem(QuickSearchListItem listItem) {
if (listItem != null) {
if (listAdapter.getCount() == 0) {
List<QuickSearchListItem> list = new ArrayList<>();
list.add(new QuickSearchTopShadowListItem(getMyApplication()));
list.add(listItem);
list.add(new QuickSearchBottomShadowListItem(getMyApplication()));
listAdapter.setListItems(list);
} else {
QuickSearchListItem lastItem = listAdapter.getItem(listAdapter.getCount() - 1);
if (lastItem.getType() == QuickSearchListItemType.BOTTOM_SHADOW) {
listAdapter.insertListItem(listItem, listAdapter.getCount() - 1);
} else {
listAdapter.addListItem(listItem);
}
}
}
}
}