From e860d11ebdb067eae8c05d0df936fd985312d0ec Mon Sep 17 00:00:00 2001 From: alexzatsepin Date: Tue, 4 Aug 2020 20:55:23 +0300 Subject: [PATCH] [android] Implemented checkin/chekout selection in toolbasr via material date picker on search screen and map --- .../res/layout/toolbar_filter_controls.xml | 2 +- android/res/layout/toolbar_with_search.xml | 6 +- .../toolbar_with_search_no_elevation.xml | 6 +- android/res/values/donottranslate.xml | 2 +- .../src/com/mapswithme/maps/MwmActivity.java | 33 +++---- .../maps/search/BookingFilterParams.java | 11 +-- .../maps/search/SearchFilterController.java | 59 +++++++++--- .../maps/search/SearchFragment.java | 15 +++- .../maps/widget/SearchToolbarController.java | 90 ++++++++++++++++--- 9 files changed, 163 insertions(+), 61 deletions(-) diff --git a/android/res/layout/toolbar_filter_controls.xml b/android/res/layout/toolbar_filter_controls.xml index 6eb4d4277e..aac133ff8d 100644 --- a/android/res/layout/toolbar_filter_controls.xml +++ b/android/res/layout/toolbar_filter_controls.xml @@ -10,7 +10,7 @@ android:paddingTop="@dimen/margin_quarter_plus" android:paddingEnd="@dimen/margin_base_plus_quarter" android:paddingBottom="@dimen/margin_half_plus" - android:visibility="visible"> + android:visibility="gone"> + app:contentInsetStart="@dimen/dp_0"> + app:contentInsetStart="@dimen/dp_0"> AUTO com.mapswithme.maps.widget.placepage.ToolbarBehavior com.trafi.anchorbottomsheetbehavior.AnchorBottomSheetBehavior - + %s - %s diff --git a/android/src/com/mapswithme/maps/MwmActivity.java b/android/src/com/mapswithme/maps/MwmActivity.java index 838fe1a9a5..deb3a821cc 100644 --- a/android/src/com/mapswithme/maps/MwmActivity.java +++ b/android/src/com/mapswithme/maps/MwmActivity.java @@ -32,7 +32,6 @@ import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.recyclerview.widget.RecyclerView; import com.mapswithme.maps.Framework.PlacePageActivationListener; -import com.mapswithme.maps.base.CustomNavigateUpListener; import com.mapswithme.maps.ads.LikesManager; import com.mapswithme.maps.api.ParsedMwmRequest; import com.mapswithme.maps.auth.PassportAuthDialogFragment; @@ -40,6 +39,7 @@ import com.mapswithme.maps.background.AppBackgroundTracker; import com.mapswithme.maps.background.NotificationCandidate; import com.mapswithme.maps.background.Notifier; import com.mapswithme.maps.base.BaseMwmFragmentActivity; +import com.mapswithme.maps.base.CustomNavigateUpListener; import com.mapswithme.maps.base.NoConnectionListener; import com.mapswithme.maps.base.OnBackPressListener; import com.mapswithme.maps.bookmarks.AuthBundleFactory; @@ -434,9 +434,7 @@ public class MwmActivity extends BaseMwmFragmentActivity if (mFilterController == null || data == null) return; - // TODO: data.getParcelableExtra(FilterActivity.EXTRA_FILTER_PARAMS) is obsolete. Get filter - // filter params from toolbar. - BookingFilterParams params = null; + BookingFilterParams params = data.getParcelableExtra(FilterActivity.EXTRA_FILTER_PARAMS); HotelsFilter filter = data.getParcelableExtra(FilterActivity.EXTRA_FILTER); mFilterController.setFilterAndParams(filter, params); @@ -558,14 +556,15 @@ public class MwmActivity extends BaseMwmFragmentActivity this); mMainMenuController.initialize(findViewById(R.id.coordinator)); + mSearchController = new FloatingSearchToolbarController(this, this); + mSearchController.getToolbar().getViewTreeObserver().addOnGlobalLayoutListener(new ToolbarLayoutChangeListener()); + mSearchController.setVisibilityListener(this); + boolean isLaunchByDeepLink = getIntent().getBooleanExtra(EXTRA_LAUNCH_BY_DEEP_LINK, false); initViews(isLaunchByDeepLink); Statistics.INSTANCE.trackConnectionState(); - mSearchController = new FloatingSearchToolbarController(this, this); - mSearchController.getToolbar().getViewTreeObserver().addOnGlobalLayoutListener(new ToolbarLayoutChangeListener()); - mSearchController.setVisibilityListener(this); SearchEngine.INSTANCE.addListener(this); SharingHelper.INSTANCE.initialize(null); @@ -677,7 +676,13 @@ public class MwmActivity extends BaseMwmFragmentActivity { runSearch(); } - }, R.string.search_in_table); + + @Override + public void onFilterParamsChanged() + { + runSearch(); + } + }, R.string.search_in_table, mSearchController); } } @@ -1154,12 +1159,10 @@ public class MwmActivity extends BaseMwmFragmentActivity setupSearchQuery(data); - // TODO: data.getParcelableExtra(FilterActivity.EXTRA_FILTER_PARAMS) is obsolete. Get filter - // filter params from toolbar. - BookingFilterParams params = null; + BookingFilterParams params = data.getParcelableExtra(FilterActivity.EXTRA_FILTER_PARAMS); mFilterController.setFilterAndParams(data.getParcelableExtra(FilterActivity.EXTRA_FILTER), params); - mFilterController.updateFilterButtonVisibility(params != null); + mFilterController.updateFilterButtonsVisibility(mFilterController.isSatisfiedForSearch()); runSearch(); } @@ -1181,7 +1184,7 @@ public class MwmActivity extends BaseMwmFragmentActivity runSearch(); mSearchController.refreshToolbar(); - mFilterController.updateFilterButtonVisibility(true); + mFilterController.updateFilterButtonsVisibility(true); mFilterController.show(true, true); } @@ -1366,7 +1369,7 @@ public class MwmActivity extends BaseMwmFragmentActivity BookingFilterParams params = intent.getParcelableExtra(FilterActivity.EXTRA_FILTER_PARAMS); if (mFilterController != null && (filter != null || params != null)) { - mFilterController.updateFilterButtonVisibility(true); + mFilterController.updateFilterButtonsVisibility(true); mFilterController.show(!TextUtils.isEmpty(SearchEngine.INSTANCE.getQuery()), true); mFilterController.setFilterAndParams(filter, params); return true; @@ -2156,7 +2159,7 @@ public class MwmActivity extends BaseMwmFragmentActivity public void onResultsUpdate(SearchResult[] results, long timestamp, boolean isHotel) { if (mFilterController != null) - mFilterController.updateFilterButtonVisibility(isHotel); + mFilterController.updateFilterButtonsVisibility(isHotel); } @Override diff --git a/android/src/com/mapswithme/maps/search/BookingFilterParams.java b/android/src/com/mapswithme/maps/search/BookingFilterParams.java index 8cca6c43e2..1f1e9e8e2e 100644 --- a/android/src/com/mapswithme/maps/search/BookingFilterParams.java +++ b/android/src/com/mapswithme/maps/search/BookingFilterParams.java @@ -121,14 +121,9 @@ public class BookingFilterParams implements Parcelable return mRooms; } - - public static class Factory + public static BookingFilterParams createParams(long checkIn, long checkOut) { - @Nullable - public BookingFilterParams createParams(long checkIn, long checkOut, @NonNull Room... rooms) - { - return ConnectionState.isConnected() ? new BookingFilterParams(checkIn, checkOut, rooms) - : null; - } + return ConnectionState.isConnected() ? new BookingFilterParams(checkIn, checkOut, Room.DEFAULT) + : null; } } diff --git a/android/src/com/mapswithme/maps/search/SearchFilterController.java b/android/src/com/mapswithme/maps/search/SearchFilterController.java index c1e610c92d..0a3f119ba1 100644 --- a/android/src/com/mapswithme/maps/search/SearchFilterController.java +++ b/android/src/com/mapswithme/maps/search/SearchFilterController.java @@ -1,18 +1,19 @@ package com.mapswithme.maps.search; import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; -import androidx.core.content.ContextCompat; import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.core.content.ContextCompat; import com.mapswithme.maps.R; +import com.mapswithme.maps.widget.SearchToolbarController; import com.mapswithme.util.UiUtils; -public class SearchFilterController +public class SearchFilterController implements SearchToolbarController.FilterParamsChangedListener { private static final String STATE_HOTEL_FILTER = "state_hotel_filter"; private static final String STATE_FILTER_PARAMS = "state_filter_params"; @@ -36,6 +37,8 @@ public class SearchFilterController @Nullable private BookingFilterParams mBookingFilterParams; private boolean mHotelMode; + @NonNull + private final SearchToolbarController mToolbarController; @NonNull private final View.OnClickListener mClearListener = new View.OnClickListener() @@ -44,6 +47,7 @@ public class SearchFilterController public void onClick(View v) { setFilterAndParams(null, null); + mToolbarController.setFilterParams(null); if (mFilterListener != null) mFilterListener.onFilterClear(); } @@ -52,23 +56,41 @@ public class SearchFilterController @Nullable private final FilterListener mFilterListener; + @Override + public void onBookingParamsChanged() + { + mBookingFilterParams = mToolbarController.getFilterParams(); + if (mFilterListener != null) + mFilterListener.onFilterParamsChanged(); + } + + public boolean isSatisfiedForSearch() + { + return mFilter != null || mBookingFilterParams != null; + } + interface FilterListener { void onShowOnMapClick(); void onFilterClick(); void onFilterClear(); + void onFilterParamsChanged(); } - SearchFilterController(@NonNull View frame, @Nullable FilterListener listener) + SearchFilterController(@NonNull View frame, @Nullable FilterListener listener, + @NonNull SearchToolbarController toolbarController) { - this(frame, listener, R.string.search_show_on_map); + this(frame, listener, R.string.search_show_on_map, toolbarController); } - public SearchFilterController(@NonNull View frame, - @Nullable FilterListener listener, @StringRes int populateButtonText) + public SearchFilterController(@NonNull View frame, @Nullable FilterListener listener, + @StringRes int populateButtonText, + @NonNull SearchToolbarController toolbarController) { mFrame = frame; mFilterListener = listener; + mToolbarController = toolbarController; + mToolbarController.addBookingParamsChangedListener(this); mShowOnMap = mFrame.findViewById(R.id.show_on_map); mShowOnMap.setText(populateButtonText); mFilterButton = mFrame.findViewById(R.id.filter_button); @@ -95,10 +117,11 @@ public class SearchFilterController UiUtils.showIf(show, mDivider); } - public void updateFilterButtonVisibility(boolean isHotel) + public void updateFilterButtonsVisibility(boolean isHotel) { mHotelMode = isHotel; UiUtils.showIf(isHotel, mFilterButton); + mToolbarController.showFilterControls(isHotel); } private void initListeners() @@ -124,8 +147,9 @@ public class SearchFilterController public void setFilterAndParams(@Nullable HotelsFilter filter, @Nullable BookingFilterParams params) { mFilter = filter; - mBookingFilterParams = params; - if (mFilter != null || mBookingFilterParams != null) + if (params != null) + mToolbarController.setFilterParams(params); + if (mFilter != null) { mFilterIcon.setOnClickListener(mClearListener); mFilterIcon.setImageResource(R.drawable.ic_cancel); @@ -150,7 +174,8 @@ public class SearchFilterController public void resetFilter() { setFilterAndParams(null, null); - updateFilterButtonVisibility(false); + mToolbarController.setFilterParams(null); + updateFilterButtonsVisibility(false); } @Nullable @@ -170,7 +195,7 @@ public class SearchFilterController public void onRestoreState(@NonNull Bundle state) { setFilterAndParams(state.getParcelable(STATE_HOTEL_FILTER), state.getParcelable(STATE_FILTER_PARAMS)); - updateFilterButtonVisibility(state.getBoolean(STATE_HOTEL_FILTER_VISIBILITY, false)); + updateFilterButtonsVisibility(state.getBoolean(STATE_HOTEL_FILTER_VISIBILITY, false)); } public static class DefaultFilterListener implements FilterListener @@ -190,5 +215,11 @@ public class SearchFilterController { } + + @Override + public void onFilterParamsChanged() + { + + } } } diff --git a/android/src/com/mapswithme/maps/search/SearchFragment.java b/android/src/com/mapswithme/maps/search/SearchFragment.java index 8779ddf0dd..de2c0d1ed1 100644 --- a/android/src/com/mapswithme/maps/search/SearchFragment.java +++ b/android/src/com/mapswithme/maps/search/SearchFragment.java @@ -355,12 +355,18 @@ public class SearchFragment extends BaseMwmFragment { runSearch(); } - }); + + @Override + public void onFilterParamsChanged() + { + runSearch(); + } + }, mToolbarController); if (savedInstanceState != null) mFilterController.onRestoreState(savedInstanceState); if (mInitialHotelsFilter != null || mInitialFilterParams != null) mFilterController.setFilterAndParams(mInitialHotelsFilter, mInitialFilterParams); - mFilterController.updateFilterButtonVisibility(mInitialFilterParams != null); + mFilterController.updateFilterButtonsVisibility(mFilterController.isSatisfiedForSearch()); mSearchAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { @@ -665,9 +671,12 @@ public class SearchFragment extends BaseMwmFragment { if (mFilterController != null) { - mFilterController.updateFilterButtonVisibility(isHotel); + mFilterController.updateFilterButtonsVisibility(isHotel); if (!isHotel) + { mFilterController.setFilterAndParams(null, null); + mToolbarController.setFilterParams(null); + } } } diff --git a/android/src/com/mapswithme/maps/widget/SearchToolbarController.java b/android/src/com/mapswithme/maps/widget/SearchToolbarController.java index 05fc38e95e..2fb6595a77 100644 --- a/android/src/com/mapswithme/maps/widget/SearchToolbarController.java +++ b/android/src/com/mapswithme/maps/widget/SearchToolbarController.java @@ -3,34 +3,39 @@ package com.mapswithme.maps.widget; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Intent; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; import android.text.TextUtils; import android.text.TextWatcher; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.EditorInfo; import android.widget.EditText; -import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; import androidx.appcompat.app.AppCompatActivity; import androidx.core.util.Pair; import com.google.android.material.chip.Chip; -import com.google.android.material.datepicker.CalendarConstraints; import com.google.android.material.datepicker.MaterialDatePicker; import com.google.android.material.datepicker.MaterialPickerOnPositiveButtonClickListener; import com.mapswithme.maps.R; +import com.mapswithme.maps.search.BookingFilterParams; import com.mapswithme.util.InputUtils; import com.mapswithme.util.StringUtils; import com.mapswithme.util.UiUtils; import com.mapswithme.util.statistics.AlohaHelper; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; + public class SearchToolbarController extends ToolbarController implements View.OnClickListener { private static final int REQUEST_VOICE_RECOGNITION = 0xCA11; + public static final String DAY_OF_MONTH_PATTERN = "MMM d"; @NonNull private final View mSearchContainer; @@ -45,7 +50,7 @@ public class SearchToolbarController extends ToolbarController @Nullable private final View mFilterContainer; @Nullable - private Chip mChooseDates; + private Chip mChooseDatesChip; @Nullable private Chip mRooms; private final boolean mVoiceInputSupported = InputUtils.isVoiceInputSupported(getActivity()); @@ -59,21 +64,31 @@ public class SearchToolbarController extends ToolbarController SearchToolbarController.this.onTextChanged(s.toString()); } }; + @Nullable + private Pair mChosenDates; @NonNull private final View.OnClickListener mChooseDatesClickListener = v -> { MaterialDatePicker.Builder> builder = MaterialDatePicker.Builder.dateRangePicker(); + if (mChosenDates != null) + builder.setSelection(mChosenDates); final MaterialDatePicker picker = builder.build(); picker.addOnPositiveButtonClickListener(new MaterialPickerOnPositiveButtonClickListener() { @Override public void onPositiveButtonClick(Object selection) { - mChooseDates.setText(picker.getHeaderText()); + //noinspection unchecked + mChosenDates = (Pair) selection; + mChooseDatesChip.setText(picker.getHeaderText()); + for (FilterParamsChangedListener listener : mFilterParamsChangedListeners) + listener.onBookingParamsChanged(); } }); picker.show(((AppCompatActivity) getActivity()).getSupportFragmentManager(), picker.toString()); }; + @NonNull + private List mFilterParamsChangedListeners = new ArrayList<>(); public interface Container { @@ -83,7 +98,6 @@ public class SearchToolbarController extends ToolbarController public SearchToolbarController(View root, Activity activity) { super(root, activity); - mSearchContainer = getToolbar().findViewById(R.id.search_container); mQuery = mSearchContainer.findViewById(R.id.query); mQuery.setOnClickListener(this); @@ -104,20 +118,43 @@ public class SearchToolbarController extends ToolbarController mVoiceInput.setOnClickListener(this); mClear = mSearchContainer.findViewById(R.id.clear); mClear.setOnClickListener(this); - mFilterContainer = getToolbar().findViewById(R.id.filter_container); if (mFilterContainer != null) { - mChooseDates = mFilterContainer.findViewById(R.id.choose_dates); + mChooseDatesChip = mFilterContainer.findViewById(R.id.choose_dates); mRooms = mFilterContainer.findViewById(R.id.rooms); - mChooseDates.setOnClickListener(mChooseDatesClickListener); - mChooseDates.setOnCloseIconClickListener(mChooseDatesClickListener); + //noinspection ConstantConditions + mChooseDatesChip.setOnClickListener(mChooseDatesClickListener); + mChooseDatesChip.setOnCloseIconClickListener(mChooseDatesClickListener); } showProgress(false); updateButtons(true); } + public void setFilterParams(@Nullable BookingFilterParams params) + { + if (mChooseDatesChip == null) + return; + + if (params == null) + { + mChooseDatesChip.setText(R.string.date_picker_сhoose_dates_cta); + mChosenDates = null; + return; + } + + mChosenDates = new Pair<>(params.getCheckinMillisec(), params.getCheckoutMillisec()); + SimpleDateFormat dateFormater = new SimpleDateFormat(DAY_OF_MONTH_PATTERN, + Locale.getDefault()); + @SuppressWarnings("ConstantConditions") + String start = dateFormater.format(new Date(mChosenDates.first)); + @SuppressWarnings("ConstantConditions") + String end = dateFormater.format(new Date(mChosenDates.second)); + mChooseDatesChip.setText(getActivity().getString(R.string.booking_filter_date_range, + start, end)); + } + private void updateButtons(boolean queryEmpty) { UiUtils.showIf(supportsVoiceSearch() && queryEmpty && mVoiceInputSupported, mVoiceInput); @@ -237,6 +274,9 @@ public class SearchToolbarController extends ToolbarController public void showFilterControls(boolean show) { + if (mFilterContainer == null) + return; + UiUtils.showIf(show, mFilterContainer); } @@ -254,4 +294,28 @@ public class SearchToolbarController extends ToolbarController { mQuery.setHint(hint); } + + public void addBookingParamsChangedListener(@NonNull FilterParamsChangedListener listener) + { + mFilterParamsChangedListeners.add(listener); + } + + public void removeBookingParamsChangedListener(@NonNull FilterParamsChangedListener listener) + { + mFilterParamsChangedListeners.remove(listener); + } + + @Nullable + public BookingFilterParams getFilterParams() + { + if (mChosenDates == null) + return null; + + return BookingFilterParams.createParams(mChosenDates.first, mChosenDates.second); + } + + public interface FilterParamsChangedListener + { + void onBookingParamsChanged(); + } }