[Quick search] UI in progress

This commit is contained in:
Alexey Kulish 2016-07-19 18:39:21 +03:00
parent 5b1af75a04
commit 40e70a04be
14 changed files with 690 additions and 184 deletions

View file

@ -113,6 +113,9 @@ public class SearchUICore {
this.onResultsComplete = onResultsComplete;
}
public SearchSettings getSearchSettings() {
return searchSettings;
}
public void updateSettings(SearchSettings settings) {
searchSettings = settings;

View file

@ -13,13 +13,12 @@
android:id="@+id/toolbar"
android:layout_width="fill_parent"
android:layout_height="@dimen/dashboard_map_toolbar"
android:background="?attr/pstsTabBackground"
android:background="?attr/bg_color"
android:minHeight="@dimen/dashboard_map_toolbar"
android:theme="?attr/toolbar_theme"
app:contentInsetLeft="54dp"
app:contentInsetStart="54dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
@ -34,6 +33,8 @@
android:background="@null"
android:gravity="center_vertical"
android:hint="@string/search_poi_category_hint"
android:textColor="?attr/searchbar_text"
android:textColorHint="?attr/searchbar_text_hint"
android:lines="1"
android:singleLine="true"/>
@ -57,18 +58,51 @@
</android.support.v7.widget.Toolbar>
<LinearLayout
android:id="@+id/tab_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/ctx_menu_info_divider"/>
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/search_tabbar_layout_theme"
app:tabGravity="fill"
app:tabMaxWidth="0dp"
app:tabMode="fixed"/>
</LinearLayout>
</android.support.design.widget.AppBarLayout>
<ListView
android:id="@android:id/list"
<LinearLayout
android:id="@+id/tabs_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginTop="0dp"
android:layout_weight="1"
android:drawSelectorOnTop="true"
android:groupIndicator="@android:color/transparent"/>
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:id="@+id/search_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone">
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>

View file

@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/listPreferredItemHeight"
android:minHeight="60dp"
android:orientation="horizontal"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
@ -59,22 +59,60 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="2dp"
android:layout_marginRight="4dp"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
android:textSize="@dimen/default_sub_text_size"
tools:text="100500 km"/>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/subtitle"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text="City"/>
android:orientation="horizontal">
<ImageView
android:id="@+id/type_name_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="4dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_small_group" />
<TextView
android:id="@+id/subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
tools:text="City"/>
<ImageView
android:id="@+id/time_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginRight="@dimen/gpx_small_icon_margin"
android:src="@drawable/ic_small_time"/>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:ellipsize="end"
android:lines="1"
android:maxLines="1"
android:scrollHorizontally="true"
tools:text="10-12 am"
android:singleLine="true"
android:textColor="?android:textColorSecondary"
android:textSize="@dimen/default_sub_text_size"/>
</LinearLayout>
</LinearLayout>

View file

@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/listPreferredItemHeight"
android:minHeight="48dp"
android:orientation="horizontal"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
@ -16,7 +16,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="?android:textColorSecondary"
android:textColor="?attr/color_dialog_buttons"
android:textSize="@dimen/default_list_text_size"
tools:text="Amsterdam"/>

View file

@ -5,6 +5,9 @@
</declare-styleable>
<declare-styleable name="OsmAndTheme">
<!-- list colors -->
<attr name="ctx_menu_info_divider" format="color"/>
<attr name="searchbar_text" format="color"/>
<attr name="searchbar_text_hint" format="color"/>
<attr name="list_divider" format="color"/>
<attr name="btn_flat_bg" format="reference" />
<attr name="expandable_list_item_background" format="color"/>
@ -40,6 +43,7 @@
<attr name="dialog_inactive_text_color" format="reference"/>
<attr name="appbar_layout_theme" format="reference"/>
<attr name="search_tabbar_layout_theme" format="reference"/>
<attr name="toolbar_theme" format="reference"/>
<attr name="new_app_theme" format="reference"/>

View file

@ -1,6 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="searchbar_text_dark">#fff</color>
<color name="searchbar_text_light">#212121</color>
<color name="searchbar_text_hint_dark">#7a8c99</color>
<color name="searchbar_text_hint_light">#727272</color>
<color name="searchbar_tab_inactive_dark">#5b6872</color>
<color name="searchbar_tab_inactive_light">#727272</color>
<color name="markers_top_bar_background">#0f5257</color>
<color name="markers_top_bar_2nd_background">#0c4347</color>
<color name="marker_top_2nd_line_color">#859899</color>

View file

@ -7,7 +7,7 @@
<dimen name="list_header_height">40dp</dimen>
<dimen name="dashboard_map_top_padding">240dp</dimen>
<dimen name="dashboard_land_width">360dp</dimen>
<dimen name="dashboard_map_toolbar">58dp</dimen>
<dimen name="dashboard_map_toolbar">56dp</dimen>
<dimen name="dash_parking_height">78dp</dimen>
<dimen name="subHeaderPadding">2dp</dimen>

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="search_categories">Categories</string>
<string name="postcode">Postcode</string>
<string name="shared_string_from">from</string>
<string name="city_type_district">District</string>

View file

@ -52,6 +52,9 @@
<!-- Osmand themes styles -->
<style name="OsmandLightTheme" parent="Theme.AppCompat.Light">
<item name="ctx_menu_info_divider">@color/ctx_menu_info_divider_light</item>
<item name="searchbar_text">@color/searchbar_text_light</item>
<item name="searchbar_text_hint">@color/searchbar_text_hint_light</item>
<item name="list_divider">@color/list_divider_dark</item>
<item name="expandable_category_color">?android:attr/colorBackground</item>
<item name="bottomToolBarColor">@color/tool_bar_color_light</item>
@ -113,6 +116,7 @@
<item name="dialog_inactive_text_color">@color/icon_color_light</item>
<item name="secondary_icon_color">@color/icon_color_light</item>
<item name="appbar_layout_theme">@style/OsmandLightTheme.DarkActionbar</item>
<item name="search_tabbar_layout_theme">@style/OsmandLightTheme.SearchTabbar</item>
<item name="toolbar_theme">@style/OsmandLightTheme.Toolbar</item>
<item name="new_app_theme">@style/OsmandLightTheme.NewAppTheme</item>
<item name="android:textColorSecondary">@color/icon_color</item>
@ -150,6 +154,14 @@
<!--<item name="actionMenuTextColor">@color/color_white</item>-->
</style>
<style name="OsmandLightTheme.SearchTabbar">
<item name="android:textColorPrimary">@color/osmand_orange</item>
<item name="colorAccent">@color/osmand_orange</item>
<item name="android:textColorSecondary">@color/searchbar_tab_inactive_light</item>
<item name="android:textColorHint">@color/searchbar_tab_inactive_light</item>
<item name="android:background">@color/ctx_menu_info_view_bg_light</item>
</style>
<style name="OsmandLightTheme.Toolbar">
<item name="android:textColorPrimary">@color/color_white</item>
<item name="android:textColorSecondary">@color/color_white</item>
@ -171,6 +183,13 @@
<item name="colorAccent">@color/color_white</item>
</style>
<style name="OsmandDarkTheme.SearchTabbar">
<item name="android:textColorPrimary">@color/osmand_orange</item>
<item name="colorAccent">@color/osmand_orange</item>
<item name="android:textColorSecondary">@color/searchbar_tab_inactive_dark</item>
<item name="android:textColorHint">@color/searchbar_tab_inactive_dark</item>
<item name="android:background">@color/ctx_menu_info_view_bg_dark</item>
</style>
<style name="OsmandLightTheme.BottomSheet">
<item name="android:dialogTheme">@style/BottomSheet.Dialog</item>
@ -196,6 +215,9 @@
</style>
<style name="OsmandDarkTheme" parent="Theme.AppCompat">
<item name="ctx_menu_info_divider">@color/ctx_menu_info_divider_dark</item>
<item name="searchbar_text">@color/searchbar_text_dark</item>
<item name="searchbar_text_hint">@color/searchbar_text_hint_dark</item>
<item name="list_divider">@color/list_divider_light</item>
<item name="expandable_category_color">?android:attr/colorBackground</item>
<item name="bottomToolBarColor">@color/tool_bar_color_dark</item>
@ -245,6 +267,7 @@
<item name="dialog_inactive_text_color">@color/dialog_inactive_text_color_dark</item>
<item name="secondary_icon_color">@color/dialog_inactive_text_color_dark</item>
<item name="appbar_layout_theme">@style/OsmandDarkTheme.DarkActionbar</item>
<item name="search_tabbar_layout_theme">@style/OsmandDarkTheme.SearchTabbar</item>
<item name="toolbar_theme">@style/OsmandDarkTheme</item>
<item name="new_app_theme">@style/OsmandDarkTheme</item>
<item name="android:textColorSecondary">@color/dash_search_icon_dark</item>

View file

@ -2,10 +2,16 @@ package net.osmand.plus.search;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.DialogFragment;
import android.support.v4.content.ContextCompat;
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.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
@ -13,7 +19,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
@ -26,12 +32,14 @@ import net.osmand.binary.BinaryMapIndexReader;
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.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;
@ -41,23 +49,34 @@ import net.osmand.search.SearchUICore.SearchResultCollection;
import net.osmand.search.SearchUICore.SearchResultMatcher;
import net.osmand.search.core.ObjectType;
import net.osmand.search.core.SearchCoreAPI;
import net.osmand.search.core.SearchCoreFactory;
import net.osmand.search.core.SearchCoreFactory.SearchAmenityTypesAPI;
import net.osmand.search.core.SearchCoreFactory.SearchBaseAPI;
import net.osmand.search.core.SearchPhrase;
import net.osmand.search.core.SearchResult;
import net.osmand.search.core.SearchSettings;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class QuickSearchDialogFragment extends DialogFragment implements OsmAndCompassListener, OsmAndLocationListener {
public static final String TAG = "QuickSearchDialogFragment";
private static final String QUICK_SEARCH_QUERY_KEY = "quick_search_query_key";
private ListView listView;
private SearchListAdapter listAdapter;
private ViewPager 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 EditText searchEditText;
private ProgressBar progressBar;
private ImageButton clearButton;
@ -88,6 +107,7 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final MapActivity mapActivity = getMapActivity();
final OsmandApplication app = getMyApplication();
final View view = inflater.inflate(R.layout.search_dialog_fragment, container, false);
if (savedInstanceState != null) {
@ -99,8 +119,12 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
if (searchQuery == null)
searchQuery = "";
tabToolbarView = view.findViewById(R.id.tab_toolbar_layout);
tabsView = view.findViewById(R.id.tabs_view);
searchView = view.findViewById(R.id.search_view);
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
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() {
@Override
@ -111,37 +135,12 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
setupSearch(mapActivity);
listView = (ListView) view.findViewById(android.R.id.list);
listAdapter = new SearchListAdapter(getMyApplication(), getActivity());
listView.setAdapter(listAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
SearchListItem item = listAdapter.getItem(position);
if (item instanceof SearchMoreListItem) {
((SearchMoreListItem) item).getOnClickListener().onClick(view);
} else {
SearchResult sr = item.getSearchResult();
viewPager = (ViewPager) view.findViewById(R.id.pager);
pagerAdapter = new SearchFragmentPagerAdapter(getChildFragmentManager(), getResources());
viewPager.setAdapter(pagerAdapter);
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;
dismiss();
if (sr.location != null) {
showOnMap(sr);
}
}
completeQueryWithObject(item.getSearchResult(), updateEditText);
}
}
});
tabLayout = (TabLayout) view.findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(viewPager);
searchEditText = (EditText) view.findViewById(R.id.searchEditText);
searchEditText.addTextChangedListener(new TextWatcher() {
@ -156,6 +155,8 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
@Override
public void afterTextChanged(Editable s) {
String newQueryText = s.toString();
updateClearButtonVisibility(newQueryText.length() > 0);
updateTabbarVisibility(newQueryText.length() == 0);
if (!searchQuery.equalsIgnoreCase(newQueryText)) {
searchQuery = newQueryText;
runSearch();
@ -165,6 +166,7 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
progressBar = (ProgressBar) view.findViewById(R.id.searchProgressBar);
clearButton = (ImageButton) view.findViewById(R.id.clearButton);
clearButton.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_remove_dark));
clearButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@ -176,13 +178,23 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
}
});
addMainSearchFragment();
searchEditText.requestFocus();
AndroidUtils.softKeyboardDelayed(searchEditText);
runSearch();
return view;
}
public void addMainSearchFragment() {
FragmentManager childFragMan = getChildFragmentManager();
FragmentTransaction childFragTrans = childFragMan.beginTransaction();
mainSearchFragment = new SearchMainListFragment();
childFragTrans.add(R.id.search_view, mainSearchFragment);
childFragTrans.addToBackStack("SearchMainListFragment");
childFragTrans.commit();
}
private void setupSearch(final MapActivity mapActivity) {
final OsmandApplication app = mapActivity.getMyApplication();
@ -234,14 +246,14 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
@Override
public void run() {
hideProgressBar();
//updateSearchResult(searchUICore.getCurrentSearchResult(), true);
addMoreButton();
}
});
}
});
// Setup favorites search api
searchUICore.registerAPI(new SearchCoreFactory.SearchBaseAPI() {
searchUICore.registerAPI(new SearchBaseAPI() {
@Override
public boolean search(SearchPhrase phrase, SearchResultMatcher resultMatcher) {
@ -271,50 +283,12 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
return SEARCH_FAVORITE_API_PRIORITY;
}
});
// Setup history search api
/*
searchUICore.registerAPI(new SearchCoreFactory.SearchBaseAPI() {
@Override
public boolean search(SearchPhrase phrase, SearchResultMatcher resultMatcher) {
SearchHistoryHelper helper = SearchHistoryHelper.getInstance((OsmandApplication) getActivity()
.getApplicationContext());
List<HistoryEntry> points = helper.getHistoryEntries();
for (HistoryEntry point : points) {
SearchResult sr = new SearchResult(phrase);
sr.localeName = point.getName().getName();
sr.object = point;
sr.priority = SEARCH_HISTORY_OBJECT_PRIORITY;
sr.objectType = ObjectType.RECENT_OBJ;
sr.location = new LatLon(point.getLat(), point.getLon());
sr.preferredZoom = 17;
if (phrase.getLastWord().length() <= 1 && phrase.isNoSelectedType()) {
resultMatcher.publish(sr);
} else if (phrase.getNameStringMatcher().matches(sr.localeName)) {
resultMatcher.publish(sr);
}
}
return true;
}
@Override
public int getSearchPriority(SearchPhrase p) {
if(!p.isNoSelectedType()) {
return -1;
}
return SEARCH_HISTORY_API_PRIORITY;
}
});
*/
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setShowsDialog(true);
final boolean isLightContent = getMyApplication().getSettings().isLightContent();
final int colorId = isLightContent ? R.color.bg_color_light : R.color.bg_color_dark;
listView.setBackgroundColor(ContextCompat.getColor(getActivity(), colorId));
}
@Override
@ -325,38 +299,134 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
@Override
public void onResume() {
super.onResume();
int screenOrientation = DashLocationFragment.getScreenOrientation(getActivity());
listAdapter.setScreenOrientation(screenOrientation);
OsmandApplication app = getMyApplication();
app.getLocationProvider().addCompassListener(this);
app.getLocationProvider().addLocationListener(this);
location = app.getLocationProvider().getLastKnownLocation();
updateLocation(location);
if (!Algorithms.isEmpty(searchQuery)) {
searchEditText.setText(searchQuery);
searchEditText.setSelection(searchQuery.length());
}
}
@Override
public void onPause() {
super.onPause();
OsmandApplication app = getMyApplication();
getChildFragmentManager().popBackStack();
app.getLocationProvider().removeLocationListener(this);
app.getLocationProvider().removeCompassListener(this);
mainSearchFragment = null;
historySearchFragment = null;
categoriesSearchFragment = null;
}
private void showProgressBar() {
clearButton.setVisibility(View.GONE);
updateClearButtonVisibility(false);
progressBar.setVisibility(View.VISIBLE);
}
private void hideProgressBar() {
clearButton.setVisibility(View.VISIBLE);
updateClearButtonVisibility(true);
progressBar.setVisibility(View.GONE);
}
private void updateClearButtonVisibility(boolean show) {
if (show) {
clearButton.setVisibility(searchEditText.length() > 0 ? View.VISIBLE : View.GONE);
} else {
clearButton.setVisibility(View.GONE);
}
}
private void updateTabbarVisibility(boolean show) {
if (show && tabsView.getVisibility() == View.GONE) {
tabToolbarView.setVisibility(View.VISIBLE);
tabsView.setVisibility(View.VISIBLE);
searchView.setVisibility(View.GONE);
} else if (!show && tabsView.getVisibility() == View.VISIBLE) {
tabToolbarView.setVisibility(View.GONE);
tabsView.setVisibility(View.GONE);
searchView.setVisibility(View.VISIBLE);
}
}
public void onSearchListFragmentResume(SearchListFragment 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, sp.getSettings().getLang()));
}
searchListFragment.updateListAdapter(rows, false);
}
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, sp.getSettings().getLang()));
}
searchListFragment.updateListAdapter(rows, false);
}
break;
case MAIN:
if (!Algorithms.isEmpty(searchQuery)) {
String txt = searchQuery;
searchQuery = "";
searchEditText.setText(txt);
searchEditText.setSelection(txt.length());
}
break;
}
}
private void runSearch() {
runSearch(searchQuery);
}
@ -368,7 +438,7 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
searchUICore.updateSettings(settings.setRadiusLevel(1));
}
SearchResultCollection c = runCoreSearch(text);
updateSearchResult(c, false, false);
updateSearchResult(c, false);
}
private SearchResultCollection runCoreSearch(String text) {
@ -414,7 +484,7 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
appended = true;
}
if (!hasRegionCollection) {
updateSearchResult(resultCollection, true, appended);
updateSearchResult(resultCollection, appended);
}
}
});
@ -435,9 +505,9 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
List<SearchResult> res = new ArrayList<>(resultCollection.getCurrentSearchResults());
res.addAll(regionResults);
SearchResultCollection resCollection = new SearchResultCollection(res, regionPhrase);
updateSearchResult(resCollection, true, true);
updateSearchResult(resCollection, true);
} else {
updateSearchResult(regionResultCollection, true, false);
updateSearchResult(regionResultCollection, false);
}
}
});
@ -467,54 +537,39 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
runCoreSearch(txt);
}
private void updateSearchResult(SearchResultCollection res, boolean addMore, boolean appended) {
private void addMoreButton() {
OsmandApplication app = getMyApplication();
if ((!searchUICore.getPhrase().getLastWord().isEmpty() || searchUICore.getPhrase().isLastWord(ObjectType.POI_TYPE))
&& searchUICore.getPhrase().getSettings().getRadiusLevel() < 7) {
QuickSearchMoreListItem moreListItem =
new QuickSearchMoreListItem(app, app.getString(R.string.search_POI_level_btn).toUpperCase(), new OnClickListener() {
@Override
public void onClick(View v) {
SearchSettings settings = searchUICore.getPhrase().getSettings();
searchUICore.updateSettings(settings.setRadiusLevel(settings.getRadiusLevel() + 1));
runCoreSearch(searchQuery);
}
});
if (mainSearchFragment != null) {
mainSearchFragment.addListItem(moreListItem);
}
}
}
private void updateSearchResult(SearchResultCollection res, boolean appended) {
OsmandApplication app = getMyApplication();
List<SearchListItem> rows = new ArrayList<>();
List<QuickSearchListItem> rows = new ArrayList<>();
if (res.getCurrentSearchResults().size() > 0) {
if (addMore) {
SearchMoreListItem moreListItem = new SearchMoreListItem(app, "Results " + res.getCurrentSearchResults().size() + ", radius " + res.getPhrase().getRadiusLevel() +
" (show more...)", new OnClickListener() {
@Override
public void onClick(View v) {
SearchSettings settings = searchUICore.getPhrase().getSettings();
searchUICore.updateSettings(settings.setRadiusLevel(settings.getRadiusLevel() + 1));
runCoreSearch(searchQuery);
updateSearchResult(new SearchResultCollection(), false, false);
}
});
rows.add(moreListItem);
}
for (final SearchResult sr : res.getCurrentSearchResults()) {
rows.add(new SearchListItem(app, sr));
rows.add(new QuickSearchListItem(app, sr, searchUICore.getPhrase().getSettings().getLang()));
}
}
updateListAdapter(rows, appended);
}
private void updateListAdapter(List<SearchListItem> listItems, boolean appended) {
listAdapter.setListItems(listItems);
if (listAdapter.getCount() > 0 && !appended) {
listView.setSelection(0);
}
}
private void showOnMap(SearchResult searchResult) {
if (searchResult.location != null) {
PointDescription pointDescription = null;
Object object = null;
switch (searchResult.objectType) {
case POI:
object = searchResult.object;
pointDescription = getMapActivity().getMapLayers().getPoiMapLayer().getObjectName(object);
break;
}
getMyApplication().getSettings().setMapLocationToShow(
searchResult.location.getLatitude(), searchResult.location.getLongitude(),
searchResult.preferredZoom, pointDescription, true, object);
MapActivity.launchMapActivityMoveToTop(getActivity());
if (mainSearchFragment != null) {
mainSearchFragment.updateListAdapter(rows, appended);
}
}
@ -622,8 +677,250 @@ public class QuickSearchDialogFragment extends DialogFragment implements OsmAndC
if (location != null) {
latLon = new LatLon(location.getLatitude(), location.getLongitude());
}
listAdapter.setLocation(latLon);
listAdapter.setHeading(heading);
listAdapter.notifyDataSetChanged();
if (mainSearchFragment != null) {
mainSearchFragment.updateLocation(latLon, heading);
}
if (historySearchFragment != null) {
historySearchFragment.updateLocation(latLon, heading);
}
if (categoriesSearchFragment != null) {
categoriesSearchFragment.updateLocation(latLon, heading);
}
}
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[] titles;
public SearchFragmentPagerAdapter(FragmentManager fm, Resources res) {
super(fm);
titles = new String[titleIds.length];
for (int i = 0; i < titleIds.length; i++) {
titles[i] = res.getString(titleIds[i]);
}
}
@Override
public int getCount() {
return fragments.length;
}
@Override
public Fragment getItem(int position) {
return Fragment.instantiate(QuickSearchDialogFragment.this.getContext(), fragments[position]);
}
@Override
public CharSequence getPageTitle(int position) {
return titles[position];
}
}
public static class SearchHistoryListFragment extends SearchListFragment {
public static final int TITLE = R.string.shared_string_history;
@Override
public SearchListFragmentType getType() {
return SearchListFragmentType.HISTORY;
}
}
public static class SearchCategoriesListFragment extends SearchListFragment {
public static final int TITLE = R.string.search_categories;
@Override
public SearchListFragmentType getType() {
return SearchListFragmentType.CATEGORIES;
}
}
public static class SearchMainListFragment extends SearchListFragment {
@Override
public SearchListFragmentType getType() {
return SearchListFragmentType.MAIN;
}
}
public static abstract class SearchListFragment extends OsmAndListFragment {
private QuickSearchDialogFragment dialogFragment;
private QuickSearchListAdapter listAdapter;
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 onListItemClick(ListView l, View view, int position, long id) {
QuickSearchListItem item = listAdapter.getItem(position);
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);
}
/*
} else if (topDividerView) {
v = ctx.getLayoutInflater().inflate(R.layout.card_top_divider, null);
AndroidUtils.setListBackground(mapActivity, v, nightMode);
} else if (bottomDividerView) {
v = ctx.getLayoutInflater().inflate(R.layout.card_bottom_divider, null);
AndroidUtils.setListBackground(mapActivity, v, nightMode);
*/
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) {
PointDescription pointDescription = null;
Object object = searchResult.object;
switch (searchResult.objectType) {
case POI:
pointDescription = getMapActivity().getMapLayers().getPoiMapLayer().getObjectName(object);
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_LOCATION, "");
break;
case LOCATION:
LatLon latLon = (LatLon) object;
pointDescription = new PointDescription(latLon.getLatitude(), latLon.getLongitude());
break;
case STREET_INTERSECTION:
pointDescription = new PointDescription(PointDescription.POINT_TYPE_LOCATION, "");
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) {
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;
public SearchHistoryAPI(OsmandApplication app) {
this.app = app;
}
@Override
public boolean search(SearchPhrase phrase, SearchResultMatcher resultMatcher) {
SearchHistoryHelper helper = SearchHistoryHelper.getInstance(app);
List<HistoryEntry> points = helper.getHistoryEntries();
for (HistoryEntry point : points) {
SearchResult sr = new SearchResult(phrase);
sr.localeName = point.getName().getName();
sr.object = point;
sr.priority = SEARCH_HISTORY_OBJECT_PRIORITY;
sr.objectType = ObjectType.RECENT_OBJ;
sr.location = new LatLon(point.getLat(), point.getLon());
sr.preferredZoom = 17;
if (phrase.getLastWord().length() <= 1 && phrase.isNoSelectedType()) {
resultMatcher.publish(sr);
} else if (phrase.getNameStringMatcher().matches(sr.localeName)) {
resultMatcher.publish(sr);
}
}
return true;
}
@Override
public int getSearchPriority(SearchPhrase p) {
if(!p.isNoSelectedType()) {
return -1;
}
return SEARCH_HISTORY_API_PRIORITY;
}
}
}

View file

@ -2,6 +2,7 @@ package net.osmand.plus.search;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -11,24 +12,27 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import net.osmand.Location;
import net.osmand.data.Amenity;
import net.osmand.data.LatLon;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.dashboard.DashLocationFragment;
import net.osmand.util.Algorithms;
import net.osmand.util.OpeningHoursParser;
import java.util.Calendar;
import java.util.List;
public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
public class QuickSearchListAdapter extends ArrayAdapter<QuickSearchListItem> {
private OsmandApplication app;
private Activity activity;
private LatLon location;
private Float heading;
private boolean hasSearchMoreItem;
private int searchMoreItemPosition;
private int screenOrientation;
public SearchListAdapter(OsmandApplication app, Activity activity) {
public QuickSearchListAdapter(OsmandApplication app, Activity activity) {
super(app, R.layout.search_list_item);
this.app = app;
this.activity = activity;
@ -58,23 +62,31 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
this.heading = heading;
}
public void setListItems(List<SearchListItem> items) {
public void setListItems(List<QuickSearchListItem> items) {
setNotifyOnChange(false);
clear();
addAll(items);
hasSearchMoreItem = items.size() > 0 && items.get(0) instanceof SearchMoreListItem;
searchMoreItemPosition = items.size() > 0 && items.get(items.size() - 1) instanceof QuickSearchMoreListItem ? items.size() - 1 : -1;
setNotifyOnChange(true);
notifyDataSetChanged();
}
public void addListItem(QuickSearchListItem item) {
setNotifyOnChange(false);
add(item);
searchMoreItemPosition = item instanceof QuickSearchMoreListItem ? getCount() - 1 : -1;
setNotifyOnChange(true);
notifyDataSetChanged();
}
@Override
public SearchListItem getItem(int position) {
public QuickSearchListItem getItem(int position) {
return super.getItem(position);
}
@Override
public int getItemViewType(int position) {
return hasSearchMoreItem && position == 0 ? 0 : 1;
return searchMoreItemPosition == position ? 0 : 1;
}
@Override
@ -84,7 +96,7 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
SearchListItem listItem = getItem(position);
QuickSearchListItem listItem = getItem(position);
int viewType = this.getItemViewType(position);
LinearLayout view;
if (viewType == 0) {
@ -115,6 +127,16 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
imageView.setImageDrawable(listItem.getIcon());
String name = listItem.getName();
title.setText(name);
Drawable typeIcon = listItem.getTypeIcon();
ImageView group = (ImageView) view.findViewById(R.id.type_name_icon);
if (typeIcon != null) {
group.setImageDrawable(typeIcon);
group.setVisibility(View.VISIBLE);
} else {
group.setVisibility(View.GONE);
}
String desc = listItem.getTypeName();
if (!Algorithms.isEmpty(desc) && !desc.equals(name)) {
subtitle.setText(desc);
@ -122,12 +144,42 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
} else {
subtitle.setVisibility(View.GONE);
}
TextView timeText = (TextView) view.findViewById(R.id.time);
ImageView timeIcon = (ImageView) view.findViewById(R.id.time_icon);
if (listItem.getSearchResult().object instanceof Amenity
&& ((Amenity) listItem.getSearchResult().object).getOpeningHours() != null) {
Amenity amenity = (Amenity) listItem.getSearchResult().object;
OpeningHoursParser.OpeningHours rs = OpeningHoursParser.parseOpenedHours(amenity.getOpeningHours());
if (rs != null) {
Calendar inst = Calendar.getInstance();
inst.setTimeInMillis(System.currentTimeMillis());
boolean worksNow = rs.isOpenedForTime(inst);
inst.setTimeInMillis(System.currentTimeMillis() + 30 * 60 * 1000); // 30 minutes later
boolean worksLater = rs.isOpenedForTime(inst);
int colorId = worksNow ? worksLater ? R.color.color_ok : R.color.color_intermediate : R.color.color_warning;
timeIcon.setVisibility(View.VISIBLE);
timeText.setVisibility(View.VISIBLE);
timeIcon.setImageDrawable(app.getIconsCache().getIcon(R.drawable.ic_small_time, colorId));
timeText.setTextColor(app.getResources().getColor(colorId));
String rt = rs.getCurrentRuleTime(inst);
timeText.setText(rt == null ? "" : rt);
} else {
timeIcon.setVisibility(View.GONE);
timeText.setVisibility(View.GONE);
}
} else {
timeIcon.setVisibility(View.GONE);
timeText.setVisibility(View.GONE);
}
updateCompassVisibility(view, listItem);
}
return view;
}
private void updateCompassVisibility(View view, SearchListItem listItem) {
private void updateCompassVisibility(View view, QuickSearchListItem listItem) {
View compassView = view.findViewById(R.id.compass_layout);
Location ll = app.getLocationProvider().getLastKnownLocation();
boolean showCompass = location != null && listItem.getSearchResult().location != null;
@ -144,7 +196,7 @@ public class SearchListAdapter extends ArrayAdapter<SearchListItem> {
}
}
private void updateDistanceDirection(View view, SearchListItem listItem) {
private void updateDistanceDirection(View view, QuickSearchListItem listItem) {
TextView distanceText = (TextView) view.findViewById(R.id.distance);
ImageView direction = (ImageView) view.findViewById(R.id.direction);

View file

@ -7,6 +7,7 @@ import net.osmand.data.Amenity;
import net.osmand.data.City;
import net.osmand.data.City.CityType;
import net.osmand.data.FavouritePoint;
import net.osmand.data.PointDescription;
import net.osmand.data.Street;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.PoiCategory;
@ -22,14 +23,16 @@ import net.osmand.plus.render.RenderingIcons;
import net.osmand.search.core.SearchResult;
import net.osmand.util.Algorithms;
public class SearchListItem {
public class QuickSearchListItem {
protected OsmandApplication app;
private SearchResult searchResult;
private String lang;
public SearchListItem(OsmandApplication app, SearchResult searchResult) {
public QuickSearchListItem(OsmandApplication app, SearchResult searchResult, String lang) {
this.app = app;
this.searchResult = searchResult;
this.lang = lang;
}
public SearchResult getSearchResult() {
@ -58,6 +61,17 @@ public class SearchListItem {
}
public String getName() {
switch (searchResult.objectType) {
case STREET_INTERSECTION:
if (!Algorithms.isEmpty(searchResult.localeRelatedObjectName)) {
return searchResult.localeName + " - " + searchResult.localeRelatedObjectName;
}
break;
case RECENT_OBJ:
HistoryEntry historyEntry = (HistoryEntry) searchResult.object;
PointDescription pd = historyEntry.getName();
return pd.getSimpleName(app, false);
}
return searchResult.localeName;
}
@ -73,7 +87,7 @@ public class SearchListItem {
if (!Algorithms.isEmpty(searchResult.localeRelatedObjectName)) {
if (searchResult.distRelatedObjectName > 0) {
return getCityTypeStr(city.getType())
+ ", "
+ " "
+ OsmAndFormatter.getFormattedDistance((float) searchResult.distRelatedObjectName, app)
+ " " + app.getString(R.string.shared_string_from) + " "
+ searchResult.localeRelatedObjectName;
@ -86,22 +100,25 @@ public class SearchListItem {
return getCityTypeStr(city.getType());
}
case STREET:
Street street = (Street) searchResult.object;
City streetCity = street.getCity();
if (!Algorithms.isEmpty(searchResult.localeRelatedObjectName)) {
if (searchResult.distRelatedObjectName > 0) {
return OsmAndFormatter.getFormattedDistance((float) searchResult.distRelatedObjectName, app)
+ " " + app.getString(R.string.shared_string_from) + " "
+ searchResult.localeRelatedObjectName;
return searchResult.localeRelatedObjectName;
}
return "";
case HOUSE:
if (searchResult.relatedObject != null) {
Street relatedStreet = (Street) searchResult.relatedObject;
if (relatedStreet.getCity() != null) {
return searchResult.localeRelatedObjectName + ", " + relatedStreet.getCity().getName(lang, true);
} else {
return searchResult.localeRelatedObjectName;
}
} else {
return getCityTypeStr(streetCity.getType()) + ", " + streetCity.getName();
}
case HOUSE:
return "";
case STREET_INTERSECTION:
Street street = (Street) searchResult.object;
if (street.getCity() != null) {
return street.getCity().getName(lang, true);
}
return "";
case POI_TYPE:
AbstractPoiType abstractPoiType = (AbstractPoiType) searchResult.object;
@ -162,6 +179,22 @@ public class SearchListItem {
return searchResult.objectType.name();
}
public Drawable getTypeIcon() {
switch (searchResult.objectType) {
case FAVORITE:
return app.getIconsCache().getThemedIcon(R.drawable.ic_small_group);
case RECENT_OBJ:
HistoryEntry historyEntry = (HistoryEntry) searchResult.object;
String typeName = historyEntry.getName().getTypeName();
if (typeName != null && !typeName.isEmpty()) {
return app.getIconsCache().getThemedIcon(R.drawable.ic_small_group);
} else {
return null;
}
}
return null;
}
public Drawable getIcon() {
switch (searchResult.objectType) {
case CITY:

View file

@ -4,13 +4,13 @@ import android.view.View.OnClickListener;
import net.osmand.plus.OsmandApplication;
public class SearchMoreListItem extends SearchListItem {
public class QuickSearchMoreListItem extends QuickSearchListItem {
private String name;
private OnClickListener onClickListener;
public SearchMoreListItem(OsmandApplication app, String name, OnClickListener onClickListener) {
super(app, null);
public QuickSearchMoreListItem(OsmandApplication app, String name, OnClickListener onClickListener) {
super(app, null, null);
this.name = name;
this.onClickListener = onClickListener;
}