Merge pull request #5099 from goblinr/MAPSME-97-ext-hotel-filters

[android] Hotel filters
This commit is contained in:
Aleksandr Zatsepin 2017-01-12 14:16:14 +03:00 committed by GitHub
commit 15c4bc0d52
62 changed files with 2227 additions and 124 deletions

View file

@ -272,7 +272,8 @@ jobject ToJavaResult(Result & result, bool hasPosition, double lat, double lon)
static_cast<jint>(result.IsOpenNow())));
jni::TScopedLocalRef name(env, jni::ToJavaString(env, result.GetString()));
jobject ret = env->NewObject(g_resultClass, g_resultConstructor, name.get(), desc.get(), ll.lat, ll.lon, ranges.get());
jobject ret = env->NewObject(g_resultClass, g_resultConstructor, name.get(), desc.get(), ll.lat,
ll.lon, ranges.get(), result.IsHotel());
ASSERT(ret, ());
return ret;
@ -307,7 +308,8 @@ void OnResults(Results const & results, long long timestamp, bool isMapAndTable,
{
jni::TScopedLocalObjectArrayRef jResults(env, BuildJavaResults(results, hasPosition, lat, lon));
env->CallVoidMethod(g_javaListener, g_updateResultsId, jResults.get(),
static_cast<jlong>(timestamp));
static_cast<jlong>(timestamp),
search::HotelsClassifier::IsHotelResults(results));
}
if (results.IsEndMarker())
@ -354,10 +356,13 @@ extern "C"
Java_com_mapswithme_maps_search_SearchEngine_nativeInit(JNIEnv * env, jobject thiz)
{
g_javaListener = env->NewGlobalRef(thiz);
g_updateResultsId = jni::GetMethodID(env, g_javaListener, "onResultsUpdate", "([Lcom/mapswithme/maps/search/SearchResult;J)V");
g_updateResultsId = jni::GetMethodID(env, g_javaListener, "onResultsUpdate",
"([Lcom/mapswithme/maps/search/SearchResult;JZ)V");
g_endResultsId = jni::GetMethodID(env, g_javaListener, "onResultsEnd", "(J)V");
g_resultClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/search/SearchResult");
g_resultConstructor = jni::GetConstructorID(env, g_resultClass, "(Ljava/lang/String;Lcom/mapswithme/maps/search/SearchResult$Description;DD[I)V");
g_resultConstructor = jni::GetConstructorID(
env, g_resultClass,
"(Ljava/lang/String;Lcom/mapswithme/maps/search/SearchResult$Description;DD[IZ)V");
g_suggestConstructor = jni::GetConstructorID(env, g_resultClass, "(Ljava/lang/String;Ljava/lang/String;DD[I)V");
g_descriptionClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/search/SearchResult$Description");
g_descriptionConstructor = jni::GetConstructorID(env, g_descriptionClass, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II)V");

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z"/>
</vector>

View file

@ -73,4 +73,16 @@
placePage:animationType="left"
placePage:docked="true"
tools:ignore="UnknownIdInLayout"/>
<include
layout="@layout/search_filter_panel"
android:layout_width="match_parent"
android:layout_height="@dimen/height_block_base"
android:layout_alignParentBottom="true"/>
<com.mapswithme.maps.search.HotelsFilterView
android:id="@+id/hotels_filter"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:visibility="gone"/>
</RelativeLayout>

View file

@ -53,6 +53,12 @@
android:visibility="gone"
tools:visibility="visible"/>
<include
layout="@layout/search_filter_panel"
android:layout_width="match_parent"
android:layout_height="@dimen/height_block_base"
android:layout_gravity="bottom"/>
<com.mapswithme.maps.widget.placepage.PlacePageView
android:id="@+id/info_box"
style="@style/MwmWidget.Floating"
@ -86,4 +92,10 @@
android:elevation="@dimen/panel_elevation"
android:visibility="gone"
tools:visibility="visible"/>
<com.mapswithme.maps.search.HotelsFilterView
android:id="@+id/hotels_filter"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:visibility="gone"/>
</RelativeLayout>

View file

@ -66,4 +66,16 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
placePage:animationType="bottom"/>
<include
layout="@layout/search_filter_panel"
android:layout_width="match_parent"
android:layout_height="@dimen/height_block_base"
android:layout_alignParentBottom="true"/>
<com.mapswithme.maps.search.HotelsFilterView
android:id="@+id/hotels_filter"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:visibility="gone"/>
</RelativeLayout>

View file

@ -1,77 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<FrameLayout
xmlns:tools="http://schemas.android.com/tools"
style="@style/MwmWidget.Floating"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar_with_search_no_elevation"
android:layout_height="match_parent">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:elevation="@dimen/margin_half_plus"
tools:targetApi="lollipop">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar_with_search_no_elevation"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
</android.support.design.widget.CollapsingToolbarLayout>
<include layout="@layout/search_filter_panel"/>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Tabs -->
<LinearLayout
android:id="@+id/tab_frame"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<!-- Tabs -->
<LinearLayout
android:id="@+id/tabs_layout"
android:orientation="vertical"
android:id="@+id/tab_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:theme="@style/ThemeOverlay.AppCompat"
android:layout_width="match_parent"
android:layout_height="@dimen/tabs_height"
android:elevation="@dimen/appbar_elevation"
app:tabIndicatorColor="?colorAccent"
app:tabMode="fixed"
app:tabGravity="fill"/>
<FrameLayout
style="@style/MwmWidget.FrameLayout.Elevation"
<View
android:id="@+id/tabs_divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="1dp"
android:background="?dividerHorizontal"/>
<android.support.v4.view.ViewPager
android:id="@+id/pages"
style="@style/MwmWidget.Floating"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
<android.support.v4.view.ViewPager
android:id="@+id/pages"
style="@style/MwmWidget.Floating"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
<!-- Results -->
<FrameLayout
android:id="@+id/results_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?windowBackgroundForced">
<include layout="@layout/recycler_default"/>
<com.mapswithme.maps.widget.PlaceholderView
android:id="@+id/placeholder"
<!-- Results -->
<FrameLayout
android:id="@+id/results_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_double_and_half"
android:paddingRight="@dimen/margin_double_and_half"
android:paddingTop="@dimen/placeholder_margin_top"
android:visibility="gone"
tools:visibility="visible"/>
</FrameLayout>
android:background="?cardBackground">
<include
layout="@layout/recycler_default"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<com.mapswithme.maps.widget.PlaceholderView
android:id="@+id/placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_double_and_half"
android:paddingRight="@dimen/margin_double_and_half"
android:paddingTop="@dimen/placeholder_margin_top"
android:visibility="gone"
tools:visibility="visible"/>
</FrameLayout>
<!-- Country download suggest fragment -->
<FrameLayout
android:id="@+id/download_suggest_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
<com.mapswithme.maps.search.HotelsFilterView
android:id="@+id/filter"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
<!-- Country download suggest fragment -->
<FrameLayout
android:id="@+id/download_suggest_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</LinearLayout>

View file

@ -0,0 +1,118 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:parentTag="FrameLayout">
<FrameLayout
android:id="@+id/fade"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_dialog_translucent"
android:alpha="0"
tools:alpha="1"/>
<RelativeLayout
android:id="@+id/frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?cardBackground"
android:layout_gravity="bottom"
android:visibility="gone"
tools:visibility="visible">
<RelativeLayout
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?cardBackground"
tools:targetApi="lollipop">
<ImageView
android:id="@+id/cancel"
android:layout_width="?attr/actionBarSize"
android:layout_height="?attr/actionBarSize"
android:scaleType="centerInside"
android:src="@drawable/ic_close"
android:background="?clickableBackground"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_base"
android:layout_marginLeft="@dimen/margin_base"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/cancel"
android:layout_toEndOf="@id/cancel"
android:layout_toStartOf="@id/done"
android:layout_toLeftOf="@id/done"
android:textAppearance="@style/MwmTextAppearance.Toolbar.Title"
android:fontFamily="@string/robotoMedium"
android:textColor="?android:textColorPrimary"
android:text="@string/booking_filters"/>
<ImageView
android:id="@+id/done"
android:layout_width="?attr/actionBarSize"
android:layout_height="?attr/actionBarSize"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:scaleType="centerInside"
android:tint="?colorAccent"
android:src="@drawable/ic_done"
android:background="?clickableBackground"/>
</RelativeLayout>
<FrameLayout
style="@style/MwmWidget.FrameLayout.Elevation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/header"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/header">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/hotels_filter_padding"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginTop="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Body3"
android:textColor="?colorAccent"
android:fontFamily="@string/robotoMedium"
android:text="@string/booking_filters_rating"
tools:targetApi="jelly_bean"/>
<include layout="@layout/divider_horizontal"/>
<com.mapswithme.maps.search.RatingFilterView
android:id="@+id/rating"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<include layout="@layout/divider_horizontal"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginTop="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Body3"
android:textColor="?colorAccent"
android:fontFamily="@string/robotoMedium"
android:text="@string/booking_filters_price_category"
tools:targetApi="jelly_bean"/>
<include layout="@layout/divider_horizontal"/>
<com.mapswithme.maps.search.PriceFilterView
android:id="@+id/price"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<include layout="@layout/divider_horizontal"/>
</LinearLayout>
</ScrollView>
</RelativeLayout>
</merge>

View file

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
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"
tools:parentTag="LinearLayout">
<FrameLayout
android:id="@+id/low"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?clickableBackground"
android:layout_weight="1"
tools:background="?colorAccent">
<TextView
android:id="@+id/low_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?android:textColorPrimary"
android:layout_gravity="center"
android:text="@string/booking_filter_price_low"
android:fontFamily="@string/robotoMedium"
tools:textColor="?accentButtonTextColor"
tools:targetApi="jelly_bean"/>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:background="?dividerHorizontal"/>
</FrameLayout>
<FrameLayout
android:id="@+id/medium"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?clickableBackground"
android:layout_weight="1">
<TextView
android:id="@+id/medium_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?android:textColorPrimary"
android:layout_gravity="center"
android:text="@string/booking_filter_price_medium"
android:fontFamily="@string/robotoMedium"
tools:targetApi="jelly_bean"/>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:background="?dividerHorizontal"/>
</FrameLayout>
<FrameLayout
android:id="@+id/high"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?clickableBackground"
android:layout_weight="1">
<TextView
android:id="@+id/high_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?android:textColorPrimary"
android:layout_gravity="center"
android:text="@string/booking_filter_price_high"
android:fontFamily="@string/robotoMedium"
tools:targetApi="jelly_bean"/>
</FrameLayout>
</merge>

View file

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
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"
tools:parentTag="LinearLayout">
<FrameLayout
android:id="@+id/any"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?clickableBackground"
android:layout_weight="1"
tools:background="?colorAccent">
<TextView
android:id="@+id/any_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?android:textColorPrimary"
android:layout_gravity="center"
android:text="@string/booking_filters_rating_any"
android:fontFamily="@string/robotoMedium"
tools:textColor="?accentButtonTextColor"
tools:targetApi="jelly_bean"/>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:background="?dividerHorizontal"/>
</FrameLayout>
<FrameLayout
android:id="@+id/good"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?clickableBackground"
android:layout_weight="1">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center">
<TextView
android:id="@+id/good_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Body1"
android:layout_gravity="center"
android:text="@string/booking_filter_rating_num_good"
android:fontFamily="@string/robotoMedium"
android:gravity="center"
tools:targetApi="jelly_bean"/>
<TextView
android:id="@+id/good_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Body3"
android:layout_gravity="center"
android:text="@string/booking_filters_ragting_good"
android:gravity="center"/>
</LinearLayout>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:background="?dividerHorizontal"/>
</FrameLayout>
<FrameLayout
android:id="@+id/very_good"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?clickableBackground"
android:layout_weight="1">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center">
<TextView
android:id="@+id/very_good_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Body1"
android:layout_gravity="center"
android:text="@string/booking_filter_rating_num_very_good"
android:fontFamily="@string/robotoMedium"
android:gravity="center"
tools:targetApi="jelly_bean"/>
<TextView
android:id="@+id/very_good_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Body3"
android:layout_gravity="center"
android:text="@string/booking_filters_rating_very_good"
android:gravity="center"/>
</LinearLayout>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:background="?dividerHorizontal"/>
</FrameLayout>
<FrameLayout
android:id="@+id/excellent"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?clickableBackground"
android:layout_weight="1">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center">
<TextView
android:id="@+id/excellent_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Body1"
android:layout_gravity="center"
android:text="@string/booking_filter_rating_num_excellent"
android:fontFamily="@string/robotoMedium"
android:gravity="center"
tools:targetApi="jelly_bean"/>
<TextView
android:id="@+id/excellent_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Body3"
android:layout_gravity="center"
android:text="@string/booking_filters_rating_excellent"
android:gravity="center"/>
</LinearLayout>
</FrameLayout>
</merge>

View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/filter_frame"
android:layout_width="match_parent"
android:layout_height="@dimen/height_block_base"
android:padding="@dimen/margin_half"
android:background="?cardBackground"
android:clipToPadding="false"
android:visibility="gone"
tools:visibility="visible"
tools:showIn="@layout/fragment_search">
<TextView
android:id="@+id/show_on_map"
style="@style/MwmTextAppearance.Button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="@dimen/margin_half"
android:layout_centerVertical="true"
android:gravity="center"
android:background="?clickableBackground"
android:fontFamily="@string/robotoMedium"
android:textSize="@dimen/text_size_caption"
android:text="@string/search_show_on_map"
tools:targetApi="jelly_bean"/>
<RelativeLayout
android:id="@+id/filter_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingStart="@dimen/margin_half"
android:paddingEnd="@dimen/margin_half"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="?clickableBackground"
android:visibility="gone"
tools:background="?accentButtonBackground"
tools:elevation="@dimen/margin_quarter"
tools:visibility="visible">
<ImageView
android:id="@+id/filter_icon"
android:layout_width="@dimen/margin_base_plus"
android:layout_height="@dimen/margin_base_plus"
android:layout_marginEnd="@dimen/margin_half"
android:layout_marginRight="@dimen/margin_half"
android:layout_centerVertical="true"
android:scaleType="centerInside"
android:src="@drawable/ic_filter_list"
android:tint="?colorAccent"
tools:src="@drawable/ic_cancel"
tools:tint="?accentButtonTextColor"/>
<TextView
android:id="@+id/filter_text"
style="@style/MwmTextAppearance.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/filter_icon"
android:layout_toRightOf="@id/filter_icon"
android:textSize="@dimen/text_size_caption"
android:text="@string/booking_filters"
android:fontFamily="@string/robotoMedium"
android:layout_gravity="end"
tools:textColor="?accentButtonTextColor"
tools:targetApi="jelly_bean"/>
</RelativeLayout>
<include
android:id="@+id/divider"
layout="@layout/divider_horizontal"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:layout_marginLeft="@dimen/neg_margin_half"
android:layout_marginRight="@dimen/neg_margin_half"
android:layout_marginBottom="@dimen/neg_margin_half"/>
</RelativeLayout>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Android Strings File -->
<!-- Generated by Twine 0.6.0 -->
<!-- Language: w320dp -->
<resources>
<!-- SECTION: Strings -->
<!-- SECTION: Routing dialogs strings -->
<!-- SECTION: Strings for downloading map from search -->
</resources>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Android Strings File -->
<!-- Generated by Twine 0.6.0 -->
<!-- Language: w360dp -->
<resources>
<!-- SECTION: Strings -->
<!-- SECTION: Routing dialogs strings -->
<!-- SECTION: Strings for downloading map from search -->
</resources>

View file

@ -175,4 +175,6 @@
<!-- Placeholder-->
<dimen name="placeholder_margin_top">20dp</dimen>
<dimen name="placeholder_margin_top_no_image">80dp</dimen>
<dimen name="hotels_filter_padding">128dp</dimen>
</resources>

View file

@ -1065,4 +1065,10 @@
<string name="whatsnew_font_size_text">Labels on the map can be made bigger.</string>
<!-- "Translation is no needed, because it's a company name" -->
<string name="uber">Uber</string>
<string name="booking_filter_rating_num_good">7.0+</string>
<string name="booking_filter_rating_num_very_good">8.0+</string>
<string name="booking_filter_rating_num_excellent">9.0+</string>
<string name="booking_filter_price_low">$</string>
<string name="booking_filter_price_medium">$$</string>
<string name="booking_filter_price_high">$$$</string>
</resources>

View file

@ -17,6 +17,7 @@ import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
@ -60,9 +61,14 @@ import com.mapswithme.maps.routing.RoutingPlanController;
import com.mapswithme.maps.routing.RoutingPlanFragment;
import com.mapswithme.maps.routing.RoutingPlanInplaceController;
import com.mapswithme.maps.search.FloatingSearchToolbarController;
import com.mapswithme.maps.search.HotelsFilter;
import com.mapswithme.maps.search.HotelsFilterView;
import com.mapswithme.maps.search.NativeSearchListener;
import com.mapswithme.maps.search.SearchActivity;
import com.mapswithme.maps.search.SearchEngine;
import com.mapswithme.maps.search.SearchFilterController;
import com.mapswithme.maps.search.SearchFragment;
import com.mapswithme.maps.search.SearchResult;
import com.mapswithme.maps.settings.SettingsActivity;
import com.mapswithme.maps.settings.StoragePathManager;
import com.mapswithme.maps.settings.UnitLocale;
@ -107,7 +113,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
LocationHelper.UiCallback,
RoutingPlanController.OnToggleListener,
RoutingPlanController.SearchPoiTransitionListener,
FloatingSearchToolbarController.VisibilityListener
FloatingSearchToolbarController.VisibilityListener,
NativeSearchListener
{
public static final String EXTRA_TASK = "map_task";
private static final String EXTRA_CONSUMED = "mwm.extra.intent.processed";
@ -152,6 +159,9 @@ public class MwmActivity extends BaseMwmFragmentActivity
private ViewGroup mRootView;
@Nullable
private SearchFilterController mFilterController;
private boolean mIsFragmentContainer;
private boolean mIsFullscreen;
private boolean mIsFullscreenAnimating;
@ -341,10 +351,14 @@ public class MwmActivity extends BaseMwmFragmentActivity
final Bundle args = new Bundle();
args.putString(SearchActivity.EXTRA_QUERY, query);
if (mFilterController != null)
args.putParcelable(SearchActivity.EXTRA_HOTELS_FILTER, mFilterController.getFilter());
replaceFragment(SearchFragment.class, args, null);
}
else
SearchActivity.start(this, query);
{
SearchActivity.start(this, query, mFilterController != null ? mFilterController.getFilter() : null);
}
}
public void showEditor()
@ -433,6 +447,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
processIntent(getIntent());
SharingHelper.prepare();
SearchEngine.INSTANCE.addListener(this);
//TODO: uncomment after correct visible rect calculation.
//mVisibleRectMeasurer = new VisibleRectMeasurer(new VisibleRectListener() {
// @Override
@ -464,6 +480,45 @@ public class MwmActivity extends BaseMwmFragmentActivity
initMainMenu();
initOnmapDownloader();
initPositionChooser();
initFilterViews();
}
private void initFilterViews()
{
HotelsFilterView hotelsFilterView = (HotelsFilterView) findViewById(R.id.hotels_filter);
View frame = findViewById(R.id.filter_frame);
if (frame != null && hotelsFilterView != null)
{
mFilterController = new SearchFilterController(
frame, hotelsFilterView, new SearchFilterController.DefaultFilterListener()
{
@Override
public void onViewClick()
{
showSearch(mSearchController.getQuery());
}
@Override
public void onFilterClear()
{
runSearch();
}
@Override
public void onFilterDone()
{
runSearch();
}
}, R.string.search_in_table);
}
}
private void runSearch()
{
SearchEngine.searchInteractive(mSearchController.getQuery(), System.nanoTime(),
false /* isMapAndTable */,
mFilterController != null ? mFilterController.getFilter() : null);
SearchEngine.showAllResults(mSearchController.getQuery());
}
private void initPositionChooser()
@ -760,6 +815,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
// TODO move listeners attach-deattach to onStart-onStop since onDestroy isn't guaranteed.
Framework.nativeRemoveMapObjectListener();
BottomSheetHelper.free();
SearchEngine.INSTANCE.removeListener(this);
super.onDestroy();
}
@ -825,6 +881,13 @@ public class MwmActivity extends BaseMwmFragmentActivity
addTask(intent);
else if (intent.hasExtra(EXTRA_UPDATE_COUNTRIES))
showDownloader(true);
HotelsFilter filter = intent.getParcelableExtra(SearchActivity.EXTRA_HOTELS_FILTER);
if (mFilterController != null)
{
mFilterController.show(filter != null || !TextUtils.isEmpty(SearchEngine.getQuery()), true);
mFilterController.setFilter(filter);
}
}
private void addTask(Intent intent)
@ -961,6 +1024,9 @@ public class MwmActivity extends BaseMwmFragmentActivity
@Override
public void onBackPressed()
{
if (mFilterController != null && mFilterController.onBackPressed())
return;
if (getCurrentMenu().close(true))
{
mFadeView.fadeOut();
@ -1529,8 +1595,22 @@ public class MwmActivity extends BaseMwmFragmentActivity
return;
int toolbarHeight = mSearchController.getToolbar().getHeight();
adjustCompassAndTraffic(visible ? toolbarHeight: UiUtils.getStatusBarHeight(this));
adjustCompassAndTraffic(visible ? toolbarHeight : UiUtils.getStatusBarHeight(this));
setNavButtonsTopLimit(visible ? toolbarHeight : 0);
if (mFilterController != null)
mFilterController.show(visible && !TextUtils.isEmpty(SearchEngine.getQuery()), true);
}
@Override
public void onResultsUpdate(SearchResult[] results, long timestamp, boolean isHotel)
{
if (mFilterController != null)
mFilterController.updateFilterButtonVisibility(isHotel);
}
@Override
public void onResultsEnd(long timestamp)
{
}
@Override

View file

@ -3,8 +3,8 @@ package com.mapswithme.maps.base;
import android.app.Activity;
import android.content.Intent;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
@ -12,10 +12,10 @@ import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.WindowManager;
import com.mapswithme.maps.MwmApplication;
import com.mapswithme.maps.R;
import com.mapswithme.util.Config;
import com.mapswithme.util.ThemeUtils;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.Utils;
@ -54,7 +54,10 @@ public class BaseMwmFragmentActivity extends AppCompatActivity
super.onCreate(savedInstanceState);
UiUtils.setupStatusBar(this);
if (useTransparentStatusBar())
UiUtils.setupStatusBar(this);
if (useColorStatusBar())
UiUtils.setupColorStatusBar(this, getStatusBarColor());
setVolumeControlStream(AudioManager.STREAM_MUSIC);
final int layoutId = getContentLayoutResId();
@ -74,6 +77,29 @@ public class BaseMwmFragmentActivity extends AppCompatActivity
attachDefaultFragment();
}
@ColorRes
protected int getStatusBarColor()
{
String theme = Config.getCurrentUiTheme();
if (ThemeUtils.isDefaultTheme(theme))
return R.color.bg_statusbar;
if (ThemeUtils.isNightTheme(theme))
return R.color.bg_statusbar_night;
throw new IllegalArgumentException("Attempt to apply unsupported theme: " + theme);
}
protected boolean useColorStatusBar()
{
return false;
}
protected boolean useTransparentStatusBar()
{
return true;
}
@Override
protected void onPostCreate(@Nullable Bundle savedInstanceState)
{

View file

@ -1,8 +1,12 @@
package com.mapswithme.maps.search;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
public class HotelsFilter
import static com.mapswithme.maps.search.HotelsFilter.Op.FIELD_RATING;
public class HotelsFilter implements Parcelable
{
// *NOTE* keep this in sync with JNI counterpart.
public final static int TYPE_AND = 0;
@ -29,6 +33,21 @@ public class HotelsFilter
mLhs = lhs;
mRhs = rhs;
}
public And(Parcel source)
{
super(TYPE_AND);
mLhs = source.readParcelable(HotelsFilter.class.getClassLoader());
mRhs = source.readParcelable(HotelsFilter.class.getClassLoader());
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
super.writeToParcel(dest, flags);
dest.writeParcelable(mLhs, flags);
dest.writeParcelable(mRhs, flags);
}
}
public static class Or extends HotelsFilter
@ -44,6 +63,21 @@ public class HotelsFilter
mLhs = lhs;
mRhs = rhs;
}
public Or(Parcel source)
{
super(TYPE_OR);
mLhs = source.readParcelable(HotelsFilter.class.getClassLoader());
mRhs = source.readParcelable(HotelsFilter.class.getClassLoader());
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
super.writeToParcel(dest, flags);
dest.writeParcelable(mLhs, flags);
dest.writeParcelable(mRhs, flags);
}
}
public static class Op extends HotelsFilter
@ -68,6 +102,14 @@ public class HotelsFilter
mField = field;
mOp = op;
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
super.writeToParcel(dest, flags);
dest.writeInt(mField);
dest.writeInt(mOp);
}
}
public static class RatingFilter extends Op
@ -79,6 +121,19 @@ public class HotelsFilter
super(FIELD_RATING, op);
mValue = value;
}
public RatingFilter(Parcel source)
{
super(FIELD_RATING, source.readInt());
mValue = source.readFloat();
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
super.writeToParcel(dest, flags);
dest.writeFloat(mValue);
}
}
public static class PriceRateFilter extends Op
@ -90,5 +145,66 @@ public class HotelsFilter
super(FIELD_PRICE_RATE, op);
mValue = value;
}
public PriceRateFilter(Parcel source)
{
super(FIELD_PRICE_RATE, source.readInt());
mValue = source.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
super.writeToParcel(dest, flags);
dest.writeInt(mValue);
}
}
protected HotelsFilter(Parcel in)
{
mType = in.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
dest.writeInt(mType);
}
@Override
public int describeContents()
{
return 0;
}
private static HotelsFilter readFromParcel(Parcel source)
{
int type = source.readInt();
if (type == TYPE_AND)
return new And(source);
if (type == TYPE_OR)
return new Or(source);
int field = source.readInt();
if (field == FIELD_RATING)
return new RatingFilter(source);
return new PriceRateFilter(source);
}
public static final Creator<HotelsFilter> CREATOR = new Creator<HotelsFilter>()
{
@Override
public HotelsFilter createFromParcel(Parcel in)
{
return readFromParcel(in);
}
@Override
public HotelsFilter[] newArray(int size)
{
return new HotelsFilter[size];
}
};
}

View file

@ -0,0 +1,9 @@
package com.mapswithme.maps.search;
import android.support.annotation.Nullable;
interface HotelsFilterHolder
{
@Nullable
HotelsFilter getHotelsFilter();
}

View file

@ -0,0 +1,200 @@
package com.mapswithme.maps.search;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import com.mapswithme.maps.R;
import com.mapswithme.util.Animations;
public class HotelsFilterView extends FrameLayout
{
public interface HotelsFilterListener
{
void onCancel();
void onDone(@Nullable HotelsFilter filter);
}
private View mFrame;
private View mFade;
private RatingFilterView mRating;
private PriceFilterView mPrice;
@Nullable
private HotelsFilterListener mListener;
@Nullable
private HotelsFilter mFilter;
private boolean mOpened = false;
public HotelsFilterView(Context context)
{
this(context, null, 0, 0);
}
public HotelsFilterView(Context context, AttributeSet attrs)
{
this(context, attrs, 0, 0);
}
public HotelsFilterView(Context context, AttributeSet attrs, int defStyleAttr)
{
this(context, attrs, defStyleAttr, 0);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public HotelsFilterView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
LayoutInflater.from(context).inflate(R.layout.hotels_filter, this, true);
}
@Override
protected void onFinishInflate()
{
mFrame = findViewById(R.id.frame);
mFrame.setTranslationY(mFrame.getResources().getDisplayMetrics().heightPixels);
mFade = findViewById(R.id.fade);
mRating = (RatingFilterView) findViewById(R.id.rating);
mPrice = (PriceFilterView) findViewById(R.id.price);
findViewById(R.id.cancel).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if (mListener != null)
mListener.onCancel();
close();
}
});
findViewById(R.id.done).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
populateFilter();
if (mListener != null)
mListener.onDone(mFilter);
close();
}
});
}
private void populateFilter()
{
HotelsFilter.RatingFilter rating = mRating.getFilter();
HotelsFilter price = mPrice.getFilter();
if (rating == null && price == null)
{
mFilter = null;
return;
}
if (rating == null)
{
mFilter = price;
return;
}
if (price == null)
{
mFilter = rating;
return;
}
mFilter = new HotelsFilter.And(rating, price);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);
return mOpened;
}
public boolean close()
{
if (!mOpened)
return false;
mOpened = false;
Animations.fadeOutView(mFade, null);
Animations.disappearSliding(mFrame, Animations.BOTTOM, null);
return true;
}
public void open(@Nullable HotelsFilter filter)
{
if (mOpened)
return;
mOpened = true;
mFilter = filter;
updateViews();
Animations.fadeInView(mFade, null);
Animations.appearSliding(mFrame, Animations.BOTTOM, null);
}
/**
* Update views state according with current {@link #mFilter}
*
* mFilter may be null or {@link HotelsFilter.RatingFilter} or {@link HotelsFilter.PriceRateFilter}
* or {@link HotelsFilter.And} or {@link HotelsFilter.Or}.
*
* if mFilter is {@link HotelsFilter.And} then mLhs must be {@link HotelsFilter.RatingFilter} and
* mRhs must be {@link HotelsFilter.PriceRateFilter} or {@link HotelsFilter.Or} with mLhs and mRhs -
* {@link HotelsFilter.PriceRateFilter}
*
* if mFilter is {@link HotelsFilter.Or} then mLhs and mRhs must be {@link HotelsFilter.PriceRateFilter}
*/
private void updateViews()
{
if (mFilter == null)
{
mRating.update(null);
mPrice.update(null);
}
else
{
HotelsFilter.RatingFilter rating = null;
HotelsFilter price = null;
if (mFilter instanceof HotelsFilter.RatingFilter)
{
rating = (HotelsFilter.RatingFilter) mFilter;
}
else if (mFilter instanceof HotelsFilter.PriceRateFilter)
{
price = mFilter;
}
else if (mFilter instanceof HotelsFilter.And)
{
HotelsFilter.And and = (HotelsFilter.And) mFilter;
if (!(and.mLhs instanceof HotelsFilter.RatingFilter))
throw new AssertionError("And.mLhs must be RatingFilter");
rating = (HotelsFilter.RatingFilter) and.mLhs;
price = and.mRhs;
}
else if (mFilter instanceof HotelsFilter.Or)
{
price = mFilter;
}
mRating.update(rating);
mPrice.update(price);
}
}
public void setListener(@Nullable HotelsFilterListener listener)
{
mListener = listener;
}
}

View file

@ -10,7 +10,7 @@ public interface NativeSearchListener
* @param results Search results.
* @param timestamp Timestamp of search request.
*/
void onResultsUpdate(SearchResult[] results, long timestamp);
void onResultsUpdate(SearchResult[] results, long timestamp, boolean isHotel);
/**
* @param timestamp Timestamp of search request.

View file

@ -0,0 +1,243 @@
package com.mapswithme.maps.search;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.IdRes;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.mapswithme.maps.R;
import com.mapswithme.util.UiUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import static com.mapswithme.maps.search.HotelsFilter.Op.OP_EQ;
public class PriceFilterView extends LinearLayout implements View.OnClickListener
{
private static final int LOW = 1;
private static final int MEDIUM = 2;
private static final int HIGH = 3;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ LOW, MEDIUM, HIGH })
public @interface PriceDef
{
}
private static class Item
{
@NonNull
final View mFrame;
@NonNull
final TextView mTitle;
boolean mSelected;
private Item(@NonNull View frame, @NonNull TextView title)
{
mFrame = frame;
mTitle = title;
}
void select(boolean select)
{
mSelected = select;
update();
}
void update()
{
@DrawableRes
int background = UiUtils.getStyledResourceId(mFrame.getContext(), R.attr.clickableBackground);
@ColorRes
int titleColor =
mSelected ? UiUtils.getStyledResourceId(mFrame.getContext(), R.attr.accentButtonTextColor)
: UiUtils.getStyledResourceId(mFrame.getContext(), android.R.attr.textColorPrimary);
if (!mSelected)
mFrame.setBackgroundResource(background);
else
mFrame.setBackgroundColor(ContextCompat.getColor(mFrame.getContext(),
UiUtils.getStyledResourceId(mFrame.getContext(), R.attr.colorAccent)));
mTitle.setTextColor(ContextCompat.getColor(mFrame.getContext(), titleColor));
}
}
@Nullable
private HotelsFilter mFilter;
@NonNull
private final SparseArray<Item> mItems = new SparseArray<>();
public PriceFilterView(Context context)
{
this(context, null, 0, 0);
}
public PriceFilterView(Context context, AttributeSet attrs)
{
this(context, attrs, 0, 0);
}
public PriceFilterView(Context context, AttributeSet attrs, int defStyleAttr)
{
this(context, attrs, defStyleAttr, 0);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public PriceFilterView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
setOrientation(HORIZONTAL);
LayoutInflater.from(context).inflate(R.layout.price_filter, this, true);
}
@Override
protected void onFinishInflate()
{
View low = findViewById(R.id.low);
low.setOnClickListener(this);
mItems.append(R.id.low, new Item(low, (TextView) findViewById(R.id.low_title)));
View medium = findViewById(R.id.medium);
medium.setOnClickListener(this);
mItems.append(R.id.medium, new Item(medium, (TextView) findViewById(R.id.medium_title)));
View high = findViewById(R.id.high);
high.setOnClickListener(this);
mItems.append(R.id.high, new Item(high, (TextView) findViewById(R.id.high_title)));
}
public void update(@Nullable HotelsFilter filter)
{
mFilter = filter;
if (mFilter == null)
{
deselectAll();
return;
}
updateRecursive(mFilter);
}
private void updateRecursive(@NonNull HotelsFilter filter)
{
if (filter instanceof HotelsFilter.PriceRateFilter)
{
HotelsFilter.PriceRateFilter price = (HotelsFilter.PriceRateFilter) filter;
selectByValue(price.mValue);
}
else if (filter instanceof HotelsFilter.Or)
{
HotelsFilter.Or or = (HotelsFilter.Or) filter;
updateRecursive(or.mLhs);
updateRecursive(or.mRhs);
}
else
{
throw new AssertionError("Wrong hotels filter type");
}
}
private void deselectAll()
{
for (int i = 0; i < mItems.size(); ++i)
{
Item item = mItems.valueAt(i);
item.select(false);
}
}
private void selectByValue(@PriceDef int value)
{
switch (value)
{
case LOW:
select(R.id.low, true);
break;
case MEDIUM:
select(R.id.medium, true);
break;
case HIGH:
select(R.id.high, true);
break;
}
}
private void select(@IdRes int id, boolean force)
{
for (int i = 0; i < mItems.size(); ++i)
{
int key = mItems.keyAt(i);
Item item = mItems.valueAt(i);
if (key == id)
{
item.select(force || !item.mSelected);
return;
}
}
}
@Override
public void onClick(View v)
{
select(v.getId(), false);
updateFilter();
}
private void updateFilter()
{
List<HotelsFilter.PriceRateFilter> filters = new ArrayList<>();
for (int i = 0; i < mItems.size(); ++i)
{
int key = mItems.keyAt(i);
Item item = mItems.valueAt(i);
if (item.mSelected)
{
@PriceDef
int value = LOW;
switch (key)
{
case R.id.low:
value = LOW;
break;
case R.id.medium:
value = MEDIUM;
break;
case R.id.high:
value = HIGH;
break;
}
filters.add(new HotelsFilter.PriceRateFilter(OP_EQ, value));
}
}
if (filters.size() > 3)
throw new AssertionError("Wrong filters count");
mFilter = null;
for (HotelsFilter filter : filters)
{
if (mFilter == null)
mFilter = filter;
else
mFilter = new HotelsFilter.Or(mFilter, filter);
}
}
@Nullable
public HotelsFilter getFilter()
{
return mFilter;
}
}

View file

@ -0,0 +1,166 @@
package com.mapswithme.maps.search;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.mapswithme.maps.R;
import com.mapswithme.util.UiUtils;
import static com.mapswithme.maps.search.HotelsFilter.Op.OP_GE;
public class RatingFilterView extends LinearLayout implements View.OnClickListener
{
private static final float GOOD = 7.0f;
private static final float VERY_GOOD = 8.0f;
private static final float EXCELLENT = 9.0f;
private static class Item
{
@NonNull
final View mFrame;
@NonNull
final TextView mTitle;
@Nullable
final TextView mSubtitle;
private Item(@NonNull View frame, @NonNull TextView title, @Nullable TextView subtitle)
{
mFrame = frame;
mTitle = title;
mSubtitle = subtitle;
}
public void select(boolean select)
{
@DrawableRes
int background = UiUtils.getStyledResourceId(mFrame.getContext(), R.attr.clickableBackground);
@ColorRes
int titleColor =
select ? UiUtils.getStyledResourceId(mFrame.getContext(), R.attr.accentButtonTextColor)
: UiUtils.getStyledResourceId(mFrame.getContext(), android.R.attr.textColorPrimary);
@ColorRes
int subtitleColor =
select ? UiUtils.getStyledResourceId(mFrame.getContext(), android.R.attr.textColorSecondaryInverse)
: UiUtils.getStyledResourceId(mFrame.getContext(), android.R.attr.textColorSecondary);
if (!select)
mFrame.setBackgroundResource(background);
else
mFrame.setBackgroundColor(ContextCompat.getColor(mFrame.getContext(),
UiUtils.getStyledResourceId(mFrame.getContext(), R.attr.colorAccent)));
mTitle.setTextColor(ContextCompat.getColor(mFrame.getContext(), titleColor));
if (mSubtitle != null)
mSubtitle.setTextColor(ContextCompat.getColor(mFrame.getContext(), subtitleColor));
}
}
@Nullable
private HotelsFilter.RatingFilter mFilter;
@NonNull
private final SparseArray<Item> mItems = new SparseArray<>();
public RatingFilterView(Context context)
{
this(context, null, 0, 0);
}
public RatingFilterView(Context context, AttributeSet attrs)
{
this(context, attrs, 0, 0);
}
public RatingFilterView(Context context, AttributeSet attrs, int defStyleAttr)
{
this(context, attrs, defStyleAttr, 0);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public RatingFilterView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
setOrientation(HORIZONTAL);
LayoutInflater.from(context).inflate(R.layout.rating_filter, this, true);
}
@Override
protected void onFinishInflate()
{
View any = findViewById(R.id.any);
any.setOnClickListener(this);
mItems.append(R.id.any, new Item(any, (TextView) findViewById(R.id.any_title), null));
View good = findViewById(R.id.good);
good.setOnClickListener(this);
mItems.append(R.id.good, new Item(good, (TextView) findViewById(R.id.good_title),
(TextView) findViewById(R.id.good_subtitle)));
View veryGood = findViewById(R.id.very_good);
veryGood.setOnClickListener(this);
mItems.append(R.id.very_good, new Item(veryGood, (TextView) findViewById(R.id.very_good_title),
(TextView) findViewById(R.id.very_good_subtitle)));
View excellent = findViewById(R.id.excellent);
excellent.setOnClickListener(this);
mItems.append(R.id.excellent, new Item(excellent, (TextView) findViewById(R.id.excellent_title),
(TextView) findViewById(R.id.excellent_subtitle)));
}
public void update(@Nullable HotelsFilter.RatingFilter filter)
{
mFilter = filter;
if (mFilter == null)
select(R.id.any);
else if (mFilter.mValue == GOOD)
select(R.id.good);
else if (mFilter.mValue == VERY_GOOD)
select(R.id.very_good);
else if (mFilter.mValue == EXCELLENT)
select(R.id.excellent);
}
private void select(int id)
{
for (int i = 0; i < mItems.size(); ++i)
{
int key = mItems.keyAt(i);
Item item = mItems.valueAt(i);
item.select(key == id);
}
}
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.any:
update(null);
break;
case R.id.good:
update(new HotelsFilter.RatingFilter(OP_GE, GOOD));
break;
case R.id.very_good:
update(new HotelsFilter.RatingFilter(OP_GE, VERY_GOOD));
break;
case R.id.excellent:
update(new HotelsFilter.RatingFilter(OP_GE, EXCELLENT));
break;
}
}
@Nullable
public HotelsFilter.RatingFilter getFilter()
{
return mFilter;
}
}

View file

@ -1,9 +1,9 @@
package com.mapswithme.maps.search;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
@ -17,11 +17,14 @@ import com.mapswithme.util.ThemeUtils;
public class SearchActivity extends BaseMwmFragmentActivity implements CustomNavigateUpListener
{
public static final String EXTRA_QUERY = "search_query";
public static final String EXTRA_HOTELS_FILTER = "hotels_filter";
public static void start(@NonNull Activity activity, String query)
public static void start(@NonNull Activity activity, @Nullable String query,
@Nullable HotelsFilter filter)
{
final Intent i = new Intent(activity, SearchActivity.class);
i.putExtra(EXTRA_QUERY, query);
i.putExtra(EXTRA_HOTELS_FILTER, filter);
activity.startActivity(i);
activity.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
@ -39,12 +42,38 @@ public class SearchActivity extends BaseMwmFragmentActivity implements CustomNav
return SearchFragment.class;
}
@Override
protected boolean useTransparentStatusBar()
{
return false;
}
@Override
protected boolean useColorStatusBar()
{
return true;
}
@Override
public void customOnNavigateUp()
{
final FragmentManager manager = getSupportFragmentManager();
if (manager.getBackStackEntryCount() == 0)
{
for (Fragment fragment : manager.getFragments())
{
if (fragment instanceof HotelsFilterHolder)
{
HotelsFilter filter = ((HotelsFilterHolder) fragment).getHotelsFilter();
if (filter != null)
{
Intent intent = NavUtils.getParentActivityIntent(this);
intent.putExtra(EXTRA_HOTELS_FILTER, filter);
NavUtils.navigateUpTo(this, intent);
return;
}
}
}
NavUtils.navigateUpFromSameTask(this);
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
return;

View file

@ -23,9 +23,8 @@ import com.mapswithme.util.UiUtils;
class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
{
private static final int TYPE_POPULATE_BUTTON = 0;
private static final int TYPE_SUGGEST = 1;
private static final int TYPE_RESULT = 2;
private static final int TYPE_SUGGEST = 0;
private static final int TYPE_RESULT = 1;
private final SearchFragment mSearchFragment;
private SearchResult[] mResults;
@ -60,22 +59,6 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
}
}
private class PopulateResultsViewHolder extends BaseViewHolder
{
PopulateResultsViewHolder(View view)
{
super(view);
view.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
mSearchFragment.showAllResultsOnMap();
}
});
}
}
private static abstract class BaseResultViewHolder extends BaseViewHolder
{
BaseResultViewHolder(View view)
@ -254,9 +237,6 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
switch (viewType)
{
case TYPE_POPULATE_BUTTON:
return new PopulateResultsViewHolder(inflater.inflate(R.layout.item_search_populate, parent, false));
case TYPE_SUGGEST:
return new SuggestViewHolder(inflater.inflate(R.layout.item_search_suggest, parent, false));
@ -271,28 +251,12 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
@Override
public void onBindViewHolder(BaseViewHolder holder, int position)
{
if (showPopulateButton())
{
if (position == 0)
return;
position--;
}
holder.bind(mResults[position], position);
}
@Override
public int getItemViewType(int position)
{
if (showPopulateButton())
{
if (position == 0)
return TYPE_POPULATE_BUTTON;
position--;
}
switch (mResults[position].type)
{
case SearchResult.TYPE_SUGGEST:
@ -306,7 +270,7 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
}
}
private boolean showPopulateButton()
boolean showPopulateButton()
{
return (!RoutingController.get().isWaitingPoiPick() &&
mResults != null &&
@ -327,9 +291,6 @@ class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.BaseViewHolder>
if (mResults == null)
return res;
if (showPopulateButton())
res++;
res += mResults.length;
return res;
}

View file

@ -19,7 +19,8 @@ public enum SearchEngine implements NativeSearchListener,
private static String sSavedQuery;
@Override
public void onResultsUpdate(final SearchResult[] results, final long timestamp)
public void onResultsUpdate(final SearchResult[] results, final long timestamp,
final boolean isHotel)
{
UiThread.run(new Runnable()
{
@ -27,7 +28,7 @@ public enum SearchEngine implements NativeSearchListener,
public void run()
{
for (NativeSearchListener listener : mListeners)
listener.onResultsUpdate(results, timestamp);
listener.onResultsUpdate(results, timestamp, isHotel);
mListeners.finishIterate();
}
});

View file

@ -0,0 +1,217 @@
package com.mapswithme.maps.search;
import android.content.res.Resources;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.mapswithme.maps.R;
import com.mapswithme.util.UiUtils;
public class SearchFilterController
{
@NonNull
private final View mFrame;
@NonNull
private final TextView mShowOnMap;
@NonNull
private final View mFilterButton;
@NonNull
private final ImageView mFilterIcon;
@NonNull
private final TextView mFilterText;
@NonNull
private final View mDivider;
@NonNull
private final HotelsFilterView mFilterView;
@Nullable
private HotelsFilter mFilter;
private final float mElevation;
@NonNull
private final View.OnClickListener mClearListener = new View.OnClickListener()
{
@Override
public void onClick(View v)
{
setFilter(null);
if (mFilterListener != null)
mFilterListener.onFilterClear();
}
};
@Nullable
private final FilterListener mFilterListener;
interface FilterListener
{
void onViewClick();
void onFilterClick();
void onFilterClear();
void onFilterCancel();
void onFilterDone();
}
SearchFilterController(@NonNull View frame, @NonNull HotelsFilterView filter,
@Nullable FilterListener listener)
{
this(frame, filter, listener, R.string.search_show_on_map);
}
public SearchFilterController(@NonNull View frame, @NonNull HotelsFilterView filter,
@Nullable FilterListener listener,
@StringRes int populateButtonText)
{
mFrame = frame;
mFilterView = filter;
mFilterListener = listener;
mShowOnMap = (TextView) mFrame.findViewById(R.id.show_on_map);
mShowOnMap.setText(populateButtonText);
mFilterButton = mFrame.findViewById(R.id.filter_button);
mFilterIcon = (ImageView) mFilterButton.findViewById(R.id.filter_icon);
mFilterText = (TextView) mFilterButton.findViewById(R.id.filter_text);
mDivider = mFrame.findViewById(R.id.divider);
Resources res = mFrame.getResources();
mElevation = res.getDimension(R.dimen.margin_quarter);
initListeners();
}
public void show(boolean show, boolean showPopulateButton)
{
UiUtils.showIf(show, mFrame);
showPopulateButton(showPopulateButton);
}
void showPopulateButton(boolean show)
{
UiUtils.showIf(show, mShowOnMap);
}
void showDivider(boolean show)
{
UiUtils.showIf(show, mDivider);
}
public void updateFilterButtonVisibility(boolean isHotel)
{
UiUtils.showIf(isHotel, mFilterButton);
}
private void initListeners()
{
mShowOnMap.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
if (mFilterListener != null)
mFilterListener.onViewClick();
}
});
mFilterButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
mFilterView.open(getFilter());
if (mFilterListener != null)
mFilterListener.onFilterClick();
}
});
mFilterView.setListener(new HotelsFilterView.HotelsFilterListener()
{
@Override
public void onCancel()
{
if (mFilterListener != null)
mFilterListener.onFilterCancel();
}
@Override
public void onDone(@Nullable HotelsFilter filter)
{
setFilter(filter);
if (mFilterListener != null)
mFilterListener.onFilterDone();
}
});
}
@Nullable
public HotelsFilter getFilter()
{
return mFilter;
}
public void setFilter(@Nullable HotelsFilter filter)
{
mFilter = filter;
if (mFilter != null)
{
mFilterIcon.setOnClickListener(mClearListener);
mFilterIcon.setImageResource(R.drawable.ic_cancel);
mFilterIcon.setColorFilter(ContextCompat.getColor(mFrame.getContext(),
UiUtils.getStyledResourceId(mFrame.getContext(), R.attr.accentButtonTextColor)));
UiUtils.setBackgroundDrawable(mFilterButton, R.attr.accentButtonBackground);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
mFilterButton.setElevation(mElevation);
mFilterText.setTextColor(ContextCompat.getColor(mFrame.getContext(),
UiUtils.getStyledResourceId(mFrame.getContext(), R.attr.accentButtonTextColor)));
}
else
{
mFilterIcon.setOnClickListener(null);
mFilterIcon.setImageResource(R.drawable.ic_filter_list);
mFilterIcon.setColorFilter(ContextCompat.getColor(mFrame.getContext(),
UiUtils.getStyledResourceId(mFrame.getContext(), R.attr.colorAccent)));
UiUtils.setBackgroundDrawable(mFilterButton, R.attr.clickableBackground);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
mFilterButton.setElevation(0);
mFilterText.setTextColor(ContextCompat.getColor(mFrame.getContext(),
UiUtils.getStyledResourceId(mFrame.getContext(), R.attr.colorAccent)));
}
}
public boolean onBackPressed()
{
return mFilterView.close();
}
public static class DefaultFilterListener implements FilterListener
{
@Override
public void onViewClick()
{
}
@Override
public void onFilterClick()
{
}
@Override
public void onFilterClear()
{
}
@Override
public void onFilterCancel()
{
}
@Override
public void onFilterDone()
{
}
}
}

View file

@ -2,9 +2,10 @@ package com.mapswithme.maps.search;
import android.content.Intent;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
@ -21,6 +22,7 @@ import java.util.List;
import com.mapswithme.maps.Framework;
import com.mapswithme.maps.MwmActivity;
import com.mapswithme.maps.MwmApplication;
import com.mapswithme.maps.R;
import com.mapswithme.maps.base.BaseMwmFragment;
import com.mapswithme.maps.base.OnBackPressListener;
@ -33,6 +35,7 @@ import com.mapswithme.maps.location.LocationListener;
import com.mapswithme.maps.routing.RoutingController;
import com.mapswithme.maps.widget.PlaceholderView;
import com.mapswithme.maps.widget.SearchToolbarController;
import com.mapswithme.util.Animations;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.Utils;
import com.mapswithme.util.statistics.Statistics;
@ -42,8 +45,12 @@ public class SearchFragment extends BaseMwmFragment
implements OnBackPressListener,
NativeSearchListener,
SearchToolbarController.Container,
CategoriesAdapter.OnCategorySelectedListener
CategoriesAdapter.OnCategorySelectedListener,
HotelsFilterHolder
{
private static final float NESTED_SCROLL_DELTA =
-MwmApplication.get().getResources().getDimension(R.dimen.margin_half);
private long mLastQueryTimestamp;
private static class LastPosition
@ -67,6 +74,12 @@ public class SearchFragment extends BaseMwmFragment
super(root, getActivity());
}
@Override
protected boolean useExtendedToolbar()
{
return false;
}
@Override
protected void onTextChanged(String query)
{
@ -119,11 +132,26 @@ public class SearchFragment extends BaseMwmFragment
if (!onBackPressed())
super.onUpClick();
}
@Override
public void clear()
{
super.clear();
if (mFilterController != null)
{
mFilterController.setFilter(null);
mFilterController.updateFilterButtonVisibility(false);
}
}
}
private View mTabFrame;
private View mResultsFrame;
private PlaceholderView mResultsPlaceholder;
private RecyclerView mResults;
private AppBarLayout mAppBarLayout;
@Nullable
private SearchFilterController mFilterController;
private SearchToolbarController mToolbarController;
@ -143,6 +171,8 @@ public class SearchFragment extends BaseMwmFragment
private final LastPosition mLastPosition = new LastPosition();
private boolean mSearchRunning;
private String mInitialQuery;
@Nullable
private HotelsFilter mInitialHotelsFilter;
private boolean mFromRoutePlan;
private final LocationListener mLocationListener = new LocationListener.Simple()
@ -157,11 +187,34 @@ public class SearchFragment extends BaseMwmFragment
}
};
private final AppBarLayout.OnOffsetChangedListener mOffsetListener =
new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)
{
if (mFilterController == null)
return;
mFilterController.showDivider(
!(Math.abs(verticalOffset) == appBarLayout.getTotalScrollRange()));
}
};
private static boolean doShowDownloadSuggest()
{
return (MapManager.nativeGetDownloadedCount() == 0 && !MapManager.nativeIsDownloading());
}
@Override
@Nullable
public HotelsFilter getHotelsFilter()
{
if (mFilterController == null)
return null;
return mFilterController.getFilter();
}
private void showDownloadSuggest()
{
final FragmentManager fm = getChildFragmentManager();
@ -191,6 +244,9 @@ public class SearchFragment extends BaseMwmFragment
{
final boolean hasQuery = mToolbarController.hasQuery();
UiUtils.showIf(hasQuery, mResultsFrame);
if (mFilterController != null)
mFilterController.show(hasQuery && mSearchAdapter.getItemCount() != 0,
mSearchAdapter.showPopulateButton());
if (hasQuery)
hideDownloadSuggest();
@ -207,6 +263,8 @@ public class SearchFragment extends BaseMwmFragment
mToolbarController.hasQuery());
UiUtils.showIf(show, mResultsPlaceholder);
if (mFilterController != null)
mFilterController.showPopulateButton(mSearchAdapter.showPopulateButton());
}
@Override
@ -222,6 +280,7 @@ public class SearchFragment extends BaseMwmFragment
readArguments();
ViewGroup root = (ViewGroup) view;
mAppBarLayout = (AppBarLayout) root.findViewById(R.id.app_bar);
mTabFrame = root.findViewById(R.id.tab_frame);
ViewPager pager = (ViewPager) mTabFrame.findViewById(R.id.pages);
@ -231,12 +290,38 @@ public class SearchFragment extends BaseMwmFragment
final TabAdapter tabAdapter = new TabAdapter(getChildFragmentManager(), pager, tabLayout);
mResultsFrame = root.findViewById(R.id.results_frame);
RecyclerView results = (RecyclerView) mResultsFrame.findViewById(R.id.recycler);
setRecyclerScrollListener(results);
mResults = (RecyclerView) mResultsFrame.findViewById(R.id.recycler);
setRecyclerScrollListener(mResults);
mResultsPlaceholder = (PlaceholderView) mResultsFrame.findViewById(R.id.placeholder);
mResultsPlaceholder.setContent(R.drawable.img_search_nothing_found_light,
R.string.search_not_found, R.string.search_not_found_query);
mFilterController = new SearchFilterController(root.findViewById(R.id.filter_frame),
(HotelsFilterView) view.findViewById(R.id.filter),
new SearchFilterController.DefaultFilterListener()
{
@Override
public void onViewClick()
{
showAllResultsOnMap();
}
@Override
public void onFilterClear()
{
runSearch();
}
@Override
public void onFilterDone()
{
runSearch();
}
});
if (mInitialHotelsFilter != null)
mFilterController.setFilter(mInitialHotelsFilter);
mFilterController.updateFilterButtonVisibility(false);
if (mSearchAdapter == null)
{
mSearchAdapter = new SearchAdapter(this);
@ -250,14 +335,16 @@ public class SearchFragment extends BaseMwmFragment
});
}
results.setLayoutManager(new LinearLayoutManager(view.getContext()));
results.setAdapter(mSearchAdapter);
mResults.setLayoutManager(new LinearLayoutManager(view.getContext()));
mResults.setAdapter(mSearchAdapter);
updateFrames();
updateResultsPlaceholder();
if (mInitialQuery != null)
{
setQuery(mInitialQuery);
}
mToolbarController.activate();
SearchEngine.INSTANCE.addListener(this);
@ -281,6 +368,7 @@ public class SearchFragment extends BaseMwmFragment
{
super.onResume();
LocationHelper.INSTANCE.addListener(mLocationListener, true);
mAppBarLayout.addOnOffsetChangedListener(mOffsetListener);
}
@Override
@ -288,6 +376,7 @@ public class SearchFragment extends BaseMwmFragment
{
LocationHelper.INSTANCE.removeListener(mLocationListener);
super.onPause();
mAppBarLayout.removeOnOffsetChangedListener(mOffsetListener);
}
@Override
@ -318,6 +407,7 @@ public class SearchFragment extends BaseMwmFragment
return;
mInitialQuery = arguments.getString(SearchActivity.EXTRA_QUERY);
mInitialHotelsFilter = arguments.getParcelable(SearchActivity.EXTRA_HOTELS_FILTER);
mFromRoutePlan = RoutingController.get().isWaitingPoiPick();
}
@ -385,9 +475,12 @@ public class SearchFragment extends BaseMwmFragment
SearchRecents.add(query);
mLastQueryTimestamp = System.nanoTime();
// TODO (@alexzatsepin): set up hotelsFilter correctly.
HotelsFilter hotelsFilter = null;
if (mFilterController != null)
hotelsFilter = mFilterController.getFilter();
SearchEngine.searchInteractive(
query, mLastQueryTimestamp, false /* isMapAndTable */, null /* hotelsFilter */);
query, mLastQueryTimestamp, false /* isMapAndTable */, hotelsFilter);
SearchEngine.showAllResults(query);
Utils.navigateToParent(getActivity());
@ -411,18 +504,21 @@ public class SearchFragment extends BaseMwmFragment
private void runSearch()
{
HotelsFilter hotelsFilter = null;
if (mFilterController != null)
hotelsFilter = mFilterController.getFilter();
mLastQueryTimestamp = System.nanoTime();
// TODO @yunitsky Implement more elegant solution.
if (getActivity() instanceof MwmActivity)
{
SearchEngine.searchInteractive(
getQuery(), mLastQueryTimestamp, true /* isMapAndTable */, null /* hotelsFilter */);
getQuery(), mLastQueryTimestamp, true /* isMapAndTable */, hotelsFilter);
}
else
{
// TODO (@alexzatsepin): set up hotelsFilter correctly.
if (!SearchEngine.search(getQuery(), mLastQueryTimestamp, mLastPosition.valid,
mLastPosition.lat, mLastPosition.lon, null /* hotelsFilter */))
mLastPosition.lat, mLastPosition.lon, hotelsFilter))
{
return;
}
@ -435,7 +531,7 @@ public class SearchFragment extends BaseMwmFragment
}
@Override
public void onResultsUpdate(SearchResult[] results, long timestamp)
public void onResultsUpdate(SearchResult[] results, long timestamp, boolean isHotel)
{
if (!isAdded() || !mToolbarController.hasQuery())
return;
@ -445,6 +541,7 @@ public class SearchFragment extends BaseMwmFragment
updateFrames();
mSearchAdapter.refreshData(results);
mToolbarController.showProgress(true);
updateFilterButton(isHotel);
}
@Override
@ -460,6 +557,16 @@ public class SearchFragment extends BaseMwmFragment
mToolbarController.setQuery(category);
}
private void updateFilterButton(boolean isHotel)
{
if (mFilterController != null)
{
mFilterController.updateFilterButtonVisibility(isHotel);
if (!isHotel)
mFilterController.setFilter(null);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
@ -470,9 +577,12 @@ public class SearchFragment extends BaseMwmFragment
@Override
public boolean onBackPressed()
{
if (mFilterController != null && mFilterController.onBackPressed())
return true;
if (mToolbarController.hasQuery())
{
mToolbarController.clear();
Animations.nestedScrollAnimation(mResults, (int) NESTED_SCROLL_DELTA, 0);
return true;
}

View file

@ -50,21 +50,25 @@ public class SearchResult
// Consecutive pairs of indexes (each pair contains : start index, length), specifying highlighted matches of original query in result
public final int[] highlightRanges;
public final boolean isHotel;
public SearchResult(String name, String suggestion, double lat, double lon, int[] highlightRanges)
{
this.name = name;
this.suggestion = suggestion;
this.lat = lat;
this.lon = lon;
this.isHotel = false;
description = null;
type = TYPE_SUGGEST;
this.highlightRanges = highlightRanges;
}
public SearchResult(String name, Description description, double lat, double lon, int[] highlightRanges)
public SearchResult(String name, Description description, double lat, double lon, int[] highlightRanges, boolean isHotel)
{
this.name = name;
this.isHotel = isHotel;
suggestion = null;
this.lat = lat;
this.lon = lon;

View file

@ -28,10 +28,16 @@ public class ToolbarController
mActivity = activity;
mToolbar = (Toolbar) root.findViewById(getToolbarId());
UiUtils.extendViewWithStatusBar(mToolbar);
if (useExtendedToolbar())
UiUtils.extendViewWithStatusBar(mToolbar);
setupNavigationListener();
}
protected boolean useExtendedToolbar()
{
return true;
}
private void setupNavigationListener()
{
View customNavigationButton = mToolbar.findViewById(R.id.back);

View file

@ -10,6 +10,8 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.DisplayMetrics;
import android.support.v4.view.NestedScrollingChild;
import android.support.v4.view.ViewCompat;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
@ -205,6 +207,32 @@ public final class Animations
animator.start();
}
public static <T extends View & NestedScrollingChild> void nestedScrollAnimation(
@NonNull final T view, final int deltaY, final int deltaX)
{
ViewCompat.startNestedScroll(view, ViewCompat.SCROLL_AXIS_VERTICAL);
ValueAnimator animator = ValueAnimator.ofFloat(0.0f, 1.0f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
ViewCompat.dispatchNestedPreScroll(view, deltaX, deltaY, null, null);
ViewCompat.dispatchNestedScroll(view, 0, 0, 0, 0, null);
}
});
animator.addListener(new UiUtils.SimpleAnimatorListener()
{
@Override
public void onAnimationEnd(Animator animation)
{
ViewCompat.stopNestedScroll(view);
}
});
animator.setDuration(DURATION_DEFAULT);
animator.start();
}
private static void setCardBackgroundColor(@NonNull View view)
{
Context context = view.getContext();

View file

@ -7,16 +7,22 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.AnyRes;
import android.support.annotation.AttrRes;
import android.support.annotation.ColorRes;
import android.support.annotation.DimenRes;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.annotation.StyleRes;
import android.support.design.widget.TextInputLayout;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
@ -26,6 +32,7 @@ import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
@ -426,11 +433,42 @@ public final class UiUtils
decorViewGroup.addView(statusBarTintView);
}
public static void setupColorStatusBar(@NonNull Activity activity, @ColorRes int statusBarColor)
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
return;
Window window = activity.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(ContextCompat.getColor(activity, statusBarColor));
}
public static int getCompassYOffset(@NonNull Context context)
{
return getStatusBarHeight(context);
}
@AnyRes
public static int getStyledResourceId(Context context, @AttrRes int res)
{
TypedArray a = null;
try
{
a = context.obtainStyledAttributes(new int[] {res});
return a.getResourceId(0, -1);
}
finally
{
if (a != null)
a.recycle();
}
}
public static void setBackgroundDrawable(View view, @AttrRes int res)
{
view.setBackgroundResource(getStyledResourceId(view.getContext(), res));
}
// utility class
private UiUtils() {}
}

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -1794,3 +1794,15 @@
/* "Translation is no needed, because it's a company name" */
"uber" = "Uber";
"booking_filter_rating_num_good" = "7.0+";
"booking_filter_rating_num_very_good" = "8.0+";
"booking_filter_rating_num_excellent" = "9.0+";
"booking_filter_price_low" = "$";
"booking_filter_price_medium" = "$$";
"booking_filter_price_high" = "$$$";

View file

@ -65,6 +65,7 @@ public:
string const & GetCuisine() const { return m_metadata.m_cuisine; }
string const & GetHotelRating() const { return m_metadata.m_hotelRating; }
string const & GetHotelApproximatePricing() const { return m_metadata.m_hotelApproximatePricing; }
bool IsHotel() const { return m_metadata.m_isHotel; }
//@}
osm::YesNoUnknown IsOpenNow() const { return m_metadata.m_isOpenNow; }

View file

@ -22509,3 +22509,21 @@
[uber]
comment = "Translation is no needed, because it's a company name"
en = Uber
[booking_filter_rating_num_good]
en = 7.0+
[booking_filter_rating_num_very_good]
en = 8.0+
[booking_filter_rating_num_excellent]
en = 9.0+
[booking_filter_price_low]
en = $
[booking_filter_price_medium]
en = $$
[booking_filter_price_high]
en = $$$