[Quick search] added share/delete for history

This commit is contained in:
Alexey Kulish 2016-07-22 17:49:50 +03:00
parent c9200bb4ad
commit bc39b00cdb
10 changed files with 806 additions and 274 deletions

View file

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
@ -58,6 +59,58 @@
</android.support.v7.widget.Toolbar>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar_edit"
android:layout_width="fill_parent"
android:layout_height="@dimen/dashboard_map_toolbar"
android:background="@color/osmand_orange"
android:minHeight="@dimen/dashboard_map_toolbar"
android:theme="?attr/toolbar_theme"
app:contentInsetLeft="54dp"
app:contentInsetStart="54dp"
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/titleEdit"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@null"
android:gravity="center_vertical"
android:textColor="@color/color_white"
android:lines="1"
android:ellipsize="end"
android:singleLine="true"
android:text="5 selected"
android:textSize="@dimen/default_list_text_size_large"/>
<ImageButton
android:id="@+id/shareButton"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:contentDescription="@string/shared_string_share"
android:src="@drawable/ic_action_gshare_dark"/>
<ImageButton
android:id="@+id/deleteButton"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:contentDescription="@string/shared_string_delete"
android:src="@drawable/ic_action_delete_dark"/>
</LinearLayout>
</android.support.v7.widget.Toolbar>
<LinearLayout
android:id="@+id/tab_toolbar_layout"
android:layout_width="match_parent"
@ -89,7 +142,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.view.ViewPager
<net.osmand.plus.LockableViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"

View file

@ -15,14 +15,23 @@
android:paddingRight="16dp"
android:paddingTop="8dp">
<CheckBox
android:id="@+id/toggle_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginRight="20dp"
android:focusable="false"
android:visibility="gone"
tools:visibility="visible"/>
<ImageView
android:id="@+id/imageView"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginRight="8dp"
android:scaleType="centerInside"
android:visibility="visible"/>
android:scaleType="centerInside"/>
<LinearLayout
android:layout_width="match_parent"

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:minHeight="48dp"
android:paddingLeft="16dp"
android:paddingRight="16dp">
<CheckBox
android:id="@+id/toggle_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginRight="20dp"
android:focusable="false"
android:visibility="gone"
tools:visibility="visible"/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="@string/shared_string_select_all"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"/>
</LinearLayout>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider"/>
</LinearLayout>

View file

@ -9,6 +9,7 @@
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated).
PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
-->
<string name="share_history_subject">History shared via OsmAnd</string>
<string name="search_categories">Categories</string>
<string name="postcode">Postcode</string>
<string name="shared_string_from">from</string>

View file

@ -0,0 +1,41 @@
package net.osmand.plus;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
public class LockableViewPager extends ViewPager {
private boolean swipeLocked;
public LockableViewPager(Context context) {
super(context);
}
public LockableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean getSwipeLocked() {
return swipeLocked;
}
public void setSwipeLocked(boolean swipeLocked) {
this.swipeLocked = swipeLocked;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return !swipeLocked && super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return !swipeLocked && super.onInterceptTouchEvent(event);
}
@Override
public boolean canScrollHorizontally(int direction) {
return !swipeLocked && super.canScrollHorizontally(direction);
}
}

View file

@ -2,6 +2,7 @@ package net.osmand.plus.search;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Bundle;
@ -11,39 +12,37 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v4.content.FileProvider;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import net.osmand.AndroidUtils;
import net.osmand.Location;
import net.osmand.ResultMatcher;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.data.Amenity;
import net.osmand.data.FavouritePoint;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.plus.GPXUtilities.WptPt;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.GPXUtilities;
import net.osmand.plus.GPXUtilities.GPXFile;
import net.osmand.plus.LockableViewPager;
import net.osmand.plus.OsmAndLocationProvider.OsmAndCompassListener;
import net.osmand.plus.OsmAndLocationProvider.OsmAndLocationListener;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
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;
import net.osmand.plus.helpers.SearchHistoryHelper.HistoryEntry;
import net.osmand.plus.resources.RegionAddressRepository;
@ -60,6 +59,7 @@ import net.osmand.search.core.SearchSettings;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
@ -70,15 +70,19 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
public static final String TAG = "QuickSearchDialogFragment";
private static final String QUICK_SEARCH_QUERY_KEY = "quick_search_query_key";
private ViewPager viewPager;
private Toolbar toolbar;
private LockableViewPager viewPager;
private SearchFragmentPagerAdapter pagerAdapter;
private TabLayout tabLayout;
private View tabToolbarView;
private View tabsView;
private View searchView;
private SearchMainListFragment mainSearchFragment;
private SearchHistoryListFragment historySearchFragment;
private SearchCategoriesListFragment categoriesSearchFragment;
private QuickSearchMainListFragment mainSearchFragment;
private QuickSearchHistoryListFragment historySearchFragment;
private QuickSearchCategoriesListFragment categoriesSearchFragment;
private Toolbar toolbarEdit;
private TextView titleEdit;
private EditText searchEditText;
private ProgressBar progressBar;
@ -126,7 +130,7 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
tabsView = view.findViewById(R.id.tabs_view);
searchView = view.findViewById(R.id.search_view);
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
toolbar = (Toolbar) view.findViewById(R.id.toolbar);
toolbar.setNavigationIcon(app.getIconsCache().getThemedIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha));
toolbar.setNavigationContentDescription(R.string.access_shared_string_navigate_up);
toolbar.setNavigationOnClickListener(new OnClickListener() {
@ -136,9 +140,49 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
}
});
toolbarEdit = (Toolbar) view.findViewById(R.id.toolbar_edit);
toolbarEdit.setNavigationIcon(app.getIconsCache().getIcon(R.drawable.ic_action_remove_dark));
toolbarEdit.setNavigationContentDescription(R.string.shared_string_cancel);
toolbarEdit.setNavigationOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
enableSelectionMode(false, -1);
}
});
titleEdit = (TextView) view.findViewById(R.id.titleEdit);
view.findViewById(R.id.shareButton).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
List<HistoryEntry> historyEntries = new ArrayList<HistoryEntry>();
List<QuickSearchListItem> selectedItems = historySearchFragment.getListAdapter().getSelectedItems();
for (QuickSearchListItem searchListItem : selectedItems) {
HistoryEntry historyEntry = (HistoryEntry) searchListItem.getSearchResult().object;
historyEntries.add(historyEntry);
}
if (historyEntries.size() > 0) {
shareHistory(historyEntries);
enableSelectionMode(false, -1);
}
}
});
view.findViewById(R.id.deleteButton).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
SearchHistoryHelper helper = SearchHistoryHelper.getInstance(app);
List<QuickSearchListItem> selectedItems = historySearchFragment.getListAdapter().getSelectedItems();
for (QuickSearchListItem searchListItem : selectedItems) {
HistoryEntry historyEntry = (HistoryEntry) searchListItem.getSearchResult().object;
helper.remove(historyEntry);
}
reloadHistory();
enableSelectionMode(false, -1);
}
});
setupSearch(mapActivity);
viewPager = (ViewPager) view.findViewById(R.id.pager);
viewPager = (LockableViewPager) view.findViewById(R.id.pager);
pagerAdapter = new SearchFragmentPagerAdapter(getChildFragmentManager(), getResources());
viewPager.setAdapter(pagerAdapter);
@ -192,9 +236,9 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
public void addMainSearchFragment() {
FragmentManager childFragMan = getChildFragmentManager();
FragmentTransaction childFragTrans = childFragMan.beginTransaction();
mainSearchFragment = new SearchMainListFragment();
mainSearchFragment = new QuickSearchMainListFragment();
childFragTrans.add(R.id.search_view, mainSearchFragment);
childFragTrans.addToBackStack("SearchMainListFragment");
childFragTrans.addToBackStack("QuickSearchMainListFragment");
childFragTrans.commit();
}
@ -321,6 +365,10 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
categoriesSearchFragment = null;
}
public Toolbar getToolbar() {
return toolbar;
}
private void showProgressBar() {
updateClearButtonVisibility(false);
progressBar.setVisibility(View.VISIBLE);
@ -351,72 +399,17 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
}
}
public void onSearchListFragmentResume(SearchListFragment searchListFragment) {
public void onSearchListFragmentResume(QuickSearchListFragment searchListFragment) {
SearchPhrase sp;
switch (searchListFragment.getType()) {
case HISTORY:
historySearchFragment = (SearchHistoryListFragment) searchListFragment;
SearchHistoryAPI historyAPI =
new SearchHistoryAPI(getMyApplication());
final List<SearchResult> history = new ArrayList<>();
sp = new SearchPhrase(null).generateNewPhrase("", searchUICore.getSearchSettings());
historyAPI.search(sp, new SearchResultMatcher(
new ResultMatcher<SearchResult>() {
@Override
public boolean publish(SearchResult object) {
history.add(object);
return true;
}
@Override
public boolean isCancelled() {
return false;
}
}, 0, new AtomicInteger(0), -1));
if (history.size() > 0) {
searchUICore.sortSearchResults(sp, history);
List<QuickSearchListItem> rows = new ArrayList<>();
OsmandApplication app = getMyApplication();
for (SearchResult sr : history) {
rows.add(new QuickSearchListItem(app, sr));
}
searchListFragment.updateListAdapter(rows, false);
}
historySearchFragment = (QuickSearchHistoryListFragment) searchListFragment;
reloadHistory();
break;
case CATEGORIES:
categoriesSearchFragment = (SearchCategoriesListFragment) searchListFragment;
SearchAmenityTypesAPI amenityTypesAPI =
new SearchAmenityTypesAPI(getMyApplication().getPoiTypes());
final List<SearchResult> amenityTypes = new ArrayList<>();
sp = new SearchPhrase(null).generateNewPhrase("", searchUICore.getSearchSettings());
try {
amenityTypesAPI.search(sp, new SearchResultMatcher(
new ResultMatcher<SearchResult>() {
@Override
public boolean publish(SearchResult object) {
amenityTypes.add(object);
return true;
}
@Override
public boolean isCancelled() {
return false;
}
}, 0, new AtomicInteger(0), -1));
} catch (IOException e) {
e.printStackTrace();
}
if (amenityTypes.size() > 0) {
searchUICore.sortSearchResults(sp, amenityTypes);
List<QuickSearchListItem> rows = new ArrayList<>();
OsmandApplication app = getMyApplication();
for (SearchResult sr : amenityTypes) {
rows.add(new QuickSearchListItem(app, sr));
}
searchListFragment.updateListAdapter(rows, false);
}
categoriesSearchFragment = (QuickSearchCategoriesListFragment) searchListFragment;
reloadCategories();
break;
case MAIN:
@ -430,6 +423,67 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
}
}
private void reloadCategories() {
SearchAmenityTypesAPI amenityTypesAPI =
new SearchAmenityTypesAPI(getMyApplication().getPoiTypes());
final List<SearchResult> amenityTypes = new ArrayList<>();
SearchPhrase sp = new SearchPhrase(null).generateNewPhrase("", searchUICore.getSearchSettings());
try {
amenityTypesAPI.search(sp, new SearchResultMatcher(
new ResultMatcher<SearchResult>() {
@Override
public boolean publish(SearchResult object) {
amenityTypes.add(object);
return true;
}
@Override
public boolean isCancelled() {
return false;
}
}, 0, new AtomicInteger(0), -1));
} catch (IOException e) {
e.printStackTrace();
}
if (amenityTypes.size() > 0) {
searchUICore.sortSearchResults(sp, amenityTypes);
List<QuickSearchListItem> rows = new ArrayList<>();
OsmandApplication app = getMyApplication();
for (SearchResult sr : amenityTypes) {
rows.add(new QuickSearchListItem(app, sr));
}
categoriesSearchFragment.updateListAdapter(rows, false);
}
}
private void reloadHistory() {
SearchHistoryAPI historyAPI = new SearchHistoryAPI(getMyApplication());
final List<SearchResult> history = new ArrayList<>();
SearchPhrase sp = new SearchPhrase(null).generateNewPhrase("", searchUICore.getSearchSettings());
historyAPI.search(sp, new SearchResultMatcher(
new ResultMatcher<SearchResult>() {
@Override
public boolean publish(SearchResult object) {
history.add(object);
return true;
}
@Override
public boolean isCancelled() {
return false;
}
}, 0, new AtomicInteger(0), -1));
List<QuickSearchListItem> rows = new ArrayList<>();
if (history.size() > 0) {
searchUICore.sortSearchResults(sp, history);
OsmandApplication app = getMyApplication();
for (SearchResult sr : history) {
rows.add(new QuickSearchListItem(app, sr));
}
}
historySearchFragment.updateListAdapter(rows, false);
}
private void runSearch() {
runSearch(searchQuery);
}
@ -515,6 +569,9 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
}
});
break;
case PARTIAL_LOCATION:
// todo
break;
default:
results.add(object);
}
@ -529,14 +586,12 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
});
}
private void completeQueryWithObject(SearchResult sr, boolean updateEditText) {
public void completeQueryWithObject(SearchResult sr) {
searchUICore.selectSearchResult(sr);
String txt = searchUICore.getPhrase().getText(true);
if (updateEditText) {
searchQuery = txt;
searchEditText.setText(txt);
searchEditText.setSelection(txt.length());
}
searchQuery = txt;
searchEditText.setText(txt);
searchEditText.setSelection(txt.length());
runCoreSearch(txt);
}
@ -691,11 +746,78 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
}
}
public void enableSelectionMode(boolean selectionMode,int position) {
historySearchFragment.setSelectionMode(selectionMode, position);
tabToolbarView.setVisibility(selectionMode ? View.GONE : View.VISIBLE);
toolbar.setVisibility(selectionMode ? View.GONE : View.VISIBLE);
toolbarEdit.setVisibility(selectionMode ? View.VISIBLE : View.GONE);
viewPager.setSwipeLocked(selectionMode);
}
public void updateSelectionMode(List<QuickSearchListItem> selectedItems) {
if (selectedItems.size() > 0) {
String text = selectedItems.size() + " " + getMyApplication().getString(R.string.shared_string_selected_lowercase);
titleEdit.setText(text);
} else {
titleEdit.setText("");
}
}
private void shareHistory(final List<HistoryEntry> historyEntries) {
if (!historyEntries.isEmpty()) {
final AsyncTask<Void, Void, GPXFile> exportTask = new AsyncTask<Void, Void, GPXFile>() {
@Override
protected GPXFile doInBackground(Void... params) {
GPXFile gpx = new GPXFile();
for (HistoryEntry h : historyEntries) {
GPXUtilities.WptPt pt = new GPXUtilities.WptPt();
pt.lat = h.getLat();
pt.lon = h.getLon();
pt.name = h.getName().getName();
boolean hasTypeInDescription = !Algorithms.isEmpty(h.getName().getTypeName());
if (hasTypeInDescription) {
pt.desc = h.getName().getTypeName();
}
gpx.points.add(pt);
}
return gpx;
}
@Override
protected void onPreExecute() {
showProgressBar();
}
@Override
protected void onPostExecute(GPXFile gpxFile) {
hideProgressBar();
File dir = new File(getActivity().getCacheDir(), "share");
if (!dir.exists()) {
dir.mkdir();
}
File dst = new File(dir, "History.gpx");
GPXUtilities.writeGpxFile(dst, gpxFile, getMyApplication());
final Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "History.gpx:\n\n\n" + GPXUtilities.asString(gpxFile, getMyApplication()));
sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_history_subject));
sendIntent.putExtra(Intent.EXTRA_STREAM,
FileProvider.getUriForFile(getActivity(),
getActivity().getPackageName() + ".fileprovider", dst));
sendIntent.setType("text/plain");
startActivity(sendIntent);
}
};
exportTask.execute();
}
}
public class SearchFragmentPagerAdapter extends FragmentPagerAdapter {
private final String[] fragments = new String[]{SearchHistoryListFragment.class.getName(),
SearchCategoriesListFragment.class.getName()};
private final int[] titleIds = new int[]{SearchHistoryListFragment.TITLE,
SearchCategoriesListFragment.TITLE};
private final String[] fragments = new String[]{QuickSearchHistoryListFragment.class.getName(),
QuickSearchCategoriesListFragment.class.getName()};
private final int[] titleIds = new int[]{QuickSearchHistoryListFragment.TITLE,
QuickSearchCategoriesListFragment.TITLE};
private final String[] titles;
public SearchFragmentPagerAdapter(FragmentManager fm, Resources res) {
@ -722,16 +844,64 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
}
}
public static class SearchHistoryListFragment extends SearchListFragment {
public static class QuickSearchHistoryListFragment extends QuickSearchListFragment {
public static final int TITLE = R.string.shared_string_history;
private boolean selectionMode;
@Override
public SearchListFragmentType getType() {
return SearchListFragmentType.HISTORY;
}
public boolean isSelectionMode() {
return selectionMode;
}
public void setSelectionMode(boolean selectionMode, int position) {
this.selectionMode = selectionMode;
getListAdapter().setSelectionMode(selectionMode, position);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (selectionMode) {
return false;
} else {
getDialogFragment().enableSelectionMode(true, position - getListView().getHeaderViewsCount());
return true;
}
}
});
getListAdapter().setSelectionListener(new QuickSearchListAdapter.OnSelectionListener() {
@Override
public void onUpdateSelectionMode(List<QuickSearchListItem> selectedItems) {
getDialogFragment().updateSelectionMode(selectedItems);
}
@Override
public void reloadData() {
getDialogFragment().reloadHistory();
}
});
}
@Override
public void onListItemClick(ListView l, View view, int position, long id) {
if (selectionMode) {
CheckBox ch = (CheckBox) view.findViewById(R.id.toggle_item);
ch.setChecked(!ch.isChecked());
getListAdapter().toggleCheckbox(position - l.getHeaderViewsCount(), ch);
} else {
super.onListItemClick(l, view, position, id);
}
}
}
public static class SearchCategoriesListFragment extends SearchListFragment {
public static class QuickSearchCategoriesListFragment extends QuickSearchListFragment {
public static final int TITLE = R.string.search_categories;
@Override
@ -740,7 +910,7 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
}
}
public static class SearchMainListFragment extends SearchListFragment {
public static class QuickSearchMainListFragment extends QuickSearchListFragment {
@Override
public SearchListFragmentType getType() {
@ -748,176 +918,6 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
}
}
public static abstract class SearchListFragment extends OsmAndListFragment {
private QuickSearchDialogFragment dialogFragment;
private QuickSearchListAdapter listAdapter;
private boolean touching;
enum SearchListFragmentType {
HISTORY,
CATEGORIES,
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) {
View header = getLayoutInflater(savedInstanceState).inflate(R.layout.list_shadow_header, null);
View footer = getLayoutInflater(savedInstanceState).inflate(R.layout.list_shadow_footer, null);
listView.addHeaderView(header, null, false);
listView.addFooterView(footer, null, false);
}
}
@Override
public void onListItemClick(ListView l, View view, int position, long id) {
QuickSearchListItem item = listAdapter.getItem(position - l.getHeaderViewsCount());
if (item instanceof QuickSearchMoreListItem) {
((QuickSearchMoreListItem) item).getOnClickListener().onClick(view);
} else {
SearchResult sr = item.getSearchResult();
boolean updateEditText = true;
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) {
updateEditText = false;
dialogFragment.dismiss();
showOnMap(sr);
} else {
dialogFragment.completeQueryWithObject(item.getSearchResult(), updateEditText);
}
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
dialogFragment = (QuickSearchDialogFragment) getParentFragment();
listAdapter = new QuickSearchListAdapter(getMyApplication(), getActivity());
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;
}
});
}
public ArrayAdapter<?> getAdapter() {
return listAdapter;
}
@Override
public void onResume() {
super.onResume();
int screenOrientation = DashLocationFragment.getScreenOrientation(getActivity());
listAdapter.setScreenOrientation(screenOrientation);
dialogFragment.onSearchListFragmentResume(this);
}
private void showOnMap(SearchResult searchResult) {
if (searchResult.location != null) {
OsmandApplication app = getMyApplication();
PointDescription pointDescription = null;
Object object = searchResult.object;
switch (searchResult.objectType) {
case POI:
String poiSimpleFormat = OsmAndFormatter.getPoiStringWithoutType(
(Amenity) object, searchResult.requiredSearchPhrase.getSettings().getLang());
pointDescription = new PointDescription(PointDescription.POINT_TYPE_POI, poiSimpleFormat);
break;
case RECENT_OBJ:
HistoryEntry entry = (HistoryEntry) object;
pointDescription = entry.getName();
break;
case FAVORITE:
FavouritePoint fav = (FavouritePoint) object;
pointDescription = fav.getPointDescription();
break;
case HOUSE:
pointDescription = new PointDescription(PointDescription.POINT_TYPE_ADDRESS,
QuickSearchListItem.getName(app, searchResult) + ", " + QuickSearchListItem.getTypeName(app, searchResult));
break;
case LOCATION:
LatLon latLon = (LatLon) object;
pointDescription = new PointDescription(latLon.getLatitude(), latLon.getLongitude());
break;
case STREET_INTERSECTION:
pointDescription = new PointDescription(PointDescription.POINT_TYPE_ADDRESS,
QuickSearchListItem.getName(app, searchResult));
break;
case WPT:
WptPt wpt = (WptPt) object;
pointDescription = wpt.getPointDescription(getMyApplication());
break;
}
getMyApplication().getSettings().setMapLocationToShow(
searchResult.location.getLatitude(), searchResult.location.getLongitude(),
searchResult.preferredZoom, pointDescription, true, object);
MapActivity.launchMapActivityMoveToTop(getActivity());
}
}
public MapActivity getMapActivity() {
return (MapActivity)getActivity();
}
public void updateLocation(LatLon latLon, Float heading) {
if (listAdapter != null && !touching) {
listAdapter.setLocation(latLon);
listAdapter.setHeading(heading);
listAdapter.notifyDataSetChanged();
}
}
public void updateListAdapter(List<QuickSearchListItem> listItems, boolean appended) {
if (listAdapter != null) {
listAdapter.setListItems(listItems);
if (listAdapter.getCount() > 0 && !appended) {
getListView().setSelection(0);
}
}
}
public void addListItem(QuickSearchListItem listItem) {
if (listItem != null) {
listAdapter.addListItem(listItem);
}
}
}
public static class SearchHistoryAPI extends SearchBaseAPI {
private OsmandApplication app;

View file

@ -7,6 +7,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@ -21,6 +22,7 @@ import net.osmand.plus.dashboard.DashLocationFragment;
import net.osmand.util.Algorithms;
import net.osmand.util.OpeningHoursParser;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
@ -28,13 +30,33 @@ public class QuickSearchListAdapter extends ArrayAdapter<QuickSearchListItem> {
private OsmandApplication app;
private Activity activity;
private LatLon location;
private Float heading;
private int searchMoreItemPosition;
private int selectAllItemPosition;
private int screenOrientation;
private int dp56;
private int dp1;
private OnSelectionListener selectionListener;
private boolean selectionMode;
private boolean selectAll;
private List<QuickSearchListItem> selectedItems = new ArrayList<>();
private static final int ITEM_TYPE_REGULAR = 0;
private static final int ITEM_TYPE_SEARCH_MORE = 1;
private static final int ITEM_TYPE_SELECT_ALL = 2;
public interface OnSelectionListener {
void onUpdateSelectionMode(List<QuickSearchListItem> selectedItems);
void reloadData();
}
public QuickSearchListAdapter(OsmandApplication app, Activity activity) {
super(app, R.layout.search_list_item);
this.app = app;
@ -43,6 +65,14 @@ public class QuickSearchListAdapter extends ArrayAdapter<QuickSearchListItem> {
dp1 = AndroidUtils.dpToPx(app, 1f);
}
public OnSelectionListener getSelectionListener() {
return selectionListener;
}
public void setSelectionListener(OnSelectionListener selectionListener) {
this.selectionListener = selectionListener;
}
public int getScreenOrientation() {
return screenOrientation;
}
@ -67,11 +97,43 @@ public class QuickSearchListAdapter extends ArrayAdapter<QuickSearchListItem> {
this.heading = heading;
}
public boolean isSelectionMode() {
return selectionMode;
}
public void setSelectionMode(boolean selectionMode, int position) {
this.selectionMode = selectionMode;
selectAll = false;
selectedItems.clear();
if (position != -1) {
QuickSearchListItem item = getItem(position);
selectedItems.add(item);
}
if (selectionMode) {
QuickSearchSelectAllListItem selectAllListItem = new QuickSearchSelectAllListItem(app, null, null);
insertListItem(selectAllListItem, 0);
if (selectionListener != null) {
selectionListener.onUpdateSelectionMode(selectedItems);
}
} else {
if (selectionListener != null) {
selectionListener.reloadData();
}
}
//notifyDataSetInvalidated();
}
public List<QuickSearchListItem> getSelectedItems() {
return selectedItems;
}
public void setListItems(List<QuickSearchListItem> items) {
setNotifyOnChange(false);
clear();
addAll(items);
searchMoreItemPosition = items.size() > 0 && items.get(items.size() - 1) instanceof QuickSearchMoreListItem ? items.size() - 1 : -1;
for (QuickSearchListItem item : items) {
add(item);
}
acquireAdditionalItemsPositions();
setNotifyOnChange(true);
notifyDataSetChanged();
}
@ -79,11 +141,30 @@ public class QuickSearchListAdapter extends ArrayAdapter<QuickSearchListItem> {
public void addListItem(QuickSearchListItem item) {
setNotifyOnChange(false);
add(item);
searchMoreItemPosition = item instanceof QuickSearchMoreListItem ? getCount() - 1 : -1;
acquireAdditionalItemsPositions();
setNotifyOnChange(true);
notifyDataSetChanged();
}
public void insertListItem(QuickSearchListItem item, int index) {
setNotifyOnChange(false);
insert(item, index);
acquireAdditionalItemsPositions();
setNotifyOnChange(true);
notifyDataSetChanged();
}
private void acquireAdditionalItemsPositions() {
selectAllItemPosition = -1;
searchMoreItemPosition = -1;
if (getCount() > 0) {
QuickSearchListItem first = getItem(0);
QuickSearchListItem last = getItem(getCount() - 1);
selectAllItemPosition = first instanceof QuickSearchSelectAllListItem ? 0 : -1;
searchMoreItemPosition = last instanceof QuickSearchMoreListItem ? getCount() - 1 : -1;
}
}
@Override
public QuickSearchListItem getItem(int position) {
return super.getItem(position);
@ -91,20 +172,26 @@ public class QuickSearchListAdapter extends ArrayAdapter<QuickSearchListItem> {
@Override
public int getItemViewType(int position) {
return searchMoreItemPosition == position ? 0 : 1;
if (position == searchMoreItemPosition) {
return ITEM_TYPE_SEARCH_MORE;
} else if (position == selectAllItemPosition) {
return ITEM_TYPE_SELECT_ALL;
} else {
return ITEM_TYPE_REGULAR;
}
}
@Override
public int getViewTypeCount() {
return 2;
return 3;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
QuickSearchListItem listItem = getItem(position);
int viewType = this.getItemViewType(position);
public View getView(final int position, View convertView, ViewGroup parent) {
final QuickSearchListItem listItem = getItem(position);
int viewType = getItemViewType(position);
LinearLayout view;
if (viewType == 0) {
if (viewType == ITEM_TYPE_SEARCH_MORE) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) app
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@ -115,6 +202,25 @@ public class QuickSearchListAdapter extends ArrayAdapter<QuickSearchListItem> {
}
((TextView) view.findViewById(R.id.title)).setText(listItem.getName());
} else if (viewType == ITEM_TYPE_SELECT_ALL) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) app
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = (LinearLayout) inflater.inflate(
R.layout.select_all_list_item, null);
} else {
view = (LinearLayout) convertView;
}
final CheckBox ch = (CheckBox) view.findViewById(R.id.toggle_item);
ch.setVisibility(View.VISIBLE);
ch.setChecked(selectAll);
ch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toggleCheckbox(position, ch);
}
});
} else {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) app
@ -125,6 +231,21 @@ public class QuickSearchListAdapter extends ArrayAdapter<QuickSearchListItem> {
view = (LinearLayout) convertView;
}
final CheckBox ch = (CheckBox) view.findViewById(R.id.toggle_item);
if (selectionMode) {
ch.setVisibility(View.VISIBLE);
ch.setChecked(selectedItems.contains(listItem));
ch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toggleCheckbox(position, ch);
}
});
} else {
ch.setVisibility(View.GONE);
}
ImageView imageView = (ImageView) view.findViewById(R.id.imageView);
TextView title = (TextView) view.findViewById(R.id.title);
TextView subtitle = (TextView) view.findViewById(R.id.subtitle);
@ -189,7 +310,7 @@ public class QuickSearchListAdapter extends ArrayAdapter<QuickSearchListItem> {
divider.setVisibility(View.GONE);
} else {
divider.setVisibility(View.VISIBLE);
if (position + 1 == searchMoreItemPosition) {
if (position + 1 == searchMoreItemPosition || position == selectAllItemPosition) {
LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp1);
p.setMargins(0, 0, 0 ,0);
divider.setLayoutParams(p);
@ -203,6 +324,37 @@ public class QuickSearchListAdapter extends ArrayAdapter<QuickSearchListItem> {
return view;
}
public void toggleCheckbox(int position, CheckBox ch) {
int viewType = getItemViewType(position);
if (viewType == ITEM_TYPE_SELECT_ALL) {
selectAll = ch.isChecked();
if (ch.isChecked()) {
selectedItems.clear();
for (int i = 0; i < getCount(); i++) {
if (getItemViewType(i) == ITEM_TYPE_REGULAR) {
selectedItems.add(getItem(i));
}
}
} else {
selectedItems.clear();
}
notifyDataSetChanged();
if (selectionListener != null) {
selectionListener.onUpdateSelectionMode(selectedItems);
}
} else {
QuickSearchListItem listItem = getItem(position);
if (ch.isChecked()) {
selectedItems.add(listItem);
} else {
selectedItems.remove(listItem);
}
if (selectionListener != null) {
selectionListener.onUpdateSelectionMode(selectedItems);
}
}
}
private void updateCompassVisibility(View view, QuickSearchListItem listItem) {
View compassView = view.findViewById(R.id.compass_layout);
Location ll = app.getLocationProvider().getLastKnownLocation();

View file

@ -0,0 +1,204 @@
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.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import net.osmand.data.Amenity;
import net.osmand.data.FavouritePoint;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
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;
import net.osmand.search.core.ObjectType;
import net.osmand.search.core.SearchResult;
import java.util.List;
public abstract class QuickSearchListFragment extends OsmAndListFragment {
private QuickSearchDialogFragment dialogFragment;
private QuickSearchListAdapter listAdapter;
private boolean touching;
enum SearchListFragmentType {
HISTORY,
CATEGORIES,
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) {
View header = getLayoutInflater(savedInstanceState).inflate(R.layout.list_shadow_header, null);
View footer = getLayoutInflater(savedInstanceState).inflate(R.layout.list_shadow_footer, null);
listView.addHeaderView(header, null, false);
listView.addFooterView(footer, null, false);
}
}
@Override
public void onListItemClick(ListView l, View view, int position, long id) {
QuickSearchListItem item = listAdapter.getItem(position - l.getHeaderViewsCount());
if (item instanceof QuickSearchMoreListItem) {
((QuickSearchMoreListItem) item).getOnClickListener().onClick(view);
} else {
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) {
dialogFragment.dismiss();
showOnMap(sr);
} else {
dialogFragment.completeQueryWithObject(item.getSearchResult());
}
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
dialogFragment = (QuickSearchDialogFragment) getParentFragment();
listAdapter = new QuickSearchListAdapter(getMyApplication(), getActivity());
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);
}
private void showOnMap(SearchResult searchResult) {
if (searchResult.location != null) {
OsmandApplication app = getMyApplication();
PointDescription pointDescription = null;
Object object = searchResult.object;
switch (searchResult.objectType) {
case POI:
String poiSimpleFormat = OsmAndFormatter.getPoiStringWithoutType(
(Amenity) object, searchResult.requiredSearchPhrase.getSettings().getLang());
pointDescription = new PointDescription(PointDescription.POINT_TYPE_POI, poiSimpleFormat);
break;
case RECENT_OBJ:
SearchHistoryHelper.HistoryEntry entry = (SearchHistoryHelper.HistoryEntry) object;
pointDescription = entry.getName();
break;
case FAVORITE:
FavouritePoint fav = (FavouritePoint) object;
pointDescription = fav.getPointDescription();
break;
case HOUSE:
pointDescription = new PointDescription(PointDescription.POINT_TYPE_ADDRESS,
QuickSearchListItem.getName(app, searchResult) + ", " + QuickSearchListItem.getTypeName(app, searchResult));
break;
case LOCATION:
LatLon latLon = (LatLon) object;
pointDescription = new PointDescription(latLon.getLatitude(), latLon.getLongitude());
break;
case STREET_INTERSECTION:
pointDescription = new PointDescription(PointDescription.POINT_TYPE_ADDRESS,
QuickSearchListItem.getName(app, searchResult));
break;
case WPT:
GPXUtilities.WptPt wpt = (GPXUtilities.WptPt) object;
pointDescription = wpt.getPointDescription(getMyApplication());
break;
}
getMyApplication().getSettings().setMapLocationToShow(
searchResult.location.getLatitude(), searchResult.location.getLongitude(),
searchResult.preferredZoom, pointDescription, true, object);
MapActivity.launchMapActivityMoveToTop(getActivity());
}
}
public MapActivity getMapActivity() {
return (MapActivity)getActivity();
}
public void updateLocation(LatLon latLon, Float heading) {
if (listAdapter != null && !touching) {
listAdapter.setLocation(latLon);
listAdapter.setHeading(heading);
listAdapter.notifyDataSetChanged();
}
}
public void updateListAdapter(List<QuickSearchListItem> listItems, boolean appended) {
if (listAdapter != null) {
listAdapter.setListItems(listItems);
if (listAdapter.getCount() > 0 && !appended) {
getListView().setSelection(0);
}
}
}
public void addListItem(QuickSearchListItem listItem) {
if (listItem != null) {
listAdapter.addListItem(listItem);
}
}
}

View file

@ -0,0 +1,26 @@
package net.osmand.plus.search;
import android.view.View;
import net.osmand.plus.OsmandApplication;
public class QuickSearchSelectAllListItem extends QuickSearchListItem {
private String name;
private View.OnClickListener onClickListener;
public QuickSearchSelectAllListItem(OsmandApplication app, String name, View.OnClickListener onClickListener) {
super(app, null);
this.name = name;
this.onClickListener = onClickListener;
}
@Override
public String getName() {
return name;
}
public View.OnClickListener getOnClickListener() {
return onClickListener;
}
}

View file

@ -29,7 +29,9 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
public void setListItems(List<SearchListItem> items) {
setNotifyOnChange(false);
clear();
addAll(items);
for (SearchListItem item : items) {
add(item);
}
setNotifyOnChange(true);
notifyDataSetInvalidated();
}