diff --git a/android/res/layout/catalog_promo_container.xml b/android/res/layout/catalog_promo_container.xml index 7227ca7a3f..0af3f9ffa4 100644 --- a/android/res/layout/catalog_promo_container.xml +++ b/android/res/layout/catalog_promo_container.xml @@ -28,14 +28,14 @@ android:layout_height="@dimen/divider_height" layout="@layout/list_divider"/> diff --git a/android/res/values/dimens.xml b/android/res/values/dimens.xml index 4146542b17..9f03b0c907 100644 --- a/android/res/values/dimens.xml +++ b/android/res/values/dimens.xml @@ -277,5 +277,4 @@ 164dp 52dp 194dp - 28dp diff --git a/android/src/com/mapswithme/maps/bookmarks/data/MapObject.java b/android/src/com/mapswithme/maps/bookmarks/data/MapObject.java index f109342f5d..c786aeaa08 100644 --- a/android/src/com/mapswithme/maps/bookmarks/data/MapObject.java +++ b/android/src/com/mapswithme/maps/bookmarks/data/MapObject.java @@ -364,6 +364,19 @@ public class MapObject implements Parcelable, PopularityProvider return mReachableByTaxiTypes; } + @NonNull + public String[] getRawTypes() + { + String[] types = new String[0]; + if (mRawTypes != null) + { + types = new String[mRawTypes.size()]; + mRawTypes.toArray(types); + } + + return types; + } + public void setLat(double lat) { mLat = lat; diff --git a/android/src/com/mapswithme/maps/promo/CatalogPromoController.java b/android/src/com/mapswithme/maps/promo/CatalogPromoController.java new file mode 100644 index 0000000000..84ce7938ea --- /dev/null +++ b/android/src/com/mapswithme/maps/promo/CatalogPromoController.java @@ -0,0 +1,228 @@ +package com.mapswithme.maps.promo; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.text.Html; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.mapswithme.maps.R; +import com.mapswithme.maps.base.Detachable; +import com.mapswithme.maps.bookmarks.data.MapObject; +import com.mapswithme.maps.gallery.GalleryAdapter; +import com.mapswithme.maps.gallery.impl.Factory; +import com.mapswithme.maps.gallery.impl.RegularCatalogPromoListener; +import com.mapswithme.maps.widget.placepage.PlacePageView; +import com.mapswithme.maps.widget.placepage.Sponsored; +import com.mapswithme.maps.widget.recycler.ItemDecoratorFactory; +import com.mapswithme.util.NetworkPolicy; +import com.mapswithme.util.UTM; +import com.mapswithme.util.UiUtils; +import com.mapswithme.util.statistics.GalleryPlacement; +import com.mapswithme.util.statistics.GalleryType; +import com.mapswithme.util.statistics.Statistics; + +import java.util.Objects; + +public class CatalogPromoController implements Promo.Listener, Detachable +{ + @Nullable + private Activity mActivity; + @NonNull + private RecyclerView mPromoRecycler; + @NonNull + private TextView mPromoTitle; + @NonNull + private final PlacePageView mPlacePageView; + + public CatalogPromoController(@NonNull PlacePageView placePageView) + { + mPlacePageView = placePageView; + mPromoRecycler = mPlacePageView.findViewById(R.id.catalog_promo_recycler); + mPromoTitle = mPlacePageView.findViewById(R.id.catalog_promo_title); + mPromoRecycler.setNestedScrollingEnabled(false); + LinearLayoutManager layoutManager = new LinearLayoutManager(mPlacePageView.getContext(), + LinearLayoutManager.HORIZONTAL, + false); + mPromoRecycler.setLayoutManager(layoutManager); + RecyclerView.ItemDecoration decor = + ItemDecoratorFactory.createPlacePagePromoGalleryDecorator(mPlacePageView.getContext(), + LinearLayoutManager.HORIZONTAL); + mPromoRecycler.addItemDecoration(decor); + } + + @Override + public void onCityGalleryReceived(@NonNull PromoCityGallery promo) + { + if (mActivity == null) + throw new AssertionError("Activity cannot be null if promo listener is triggered!"); + + Sponsored sponsored = mPlacePageView.getSponsored(); + if (sponsored == null) + return; + + PromoResponseHandler handler = createPromoResponseHandler(promo); + if (handler == null) + return; + + handler.handleResponse(promo); + } + + @Override + public void onErrorReceived() + { + Statistics.INSTANCE.trackGalleryError(GalleryType.PROMO, GalleryPlacement.PLACEPAGE, + Statistics.ParamValue.NO_PRODUCTS); + } + + public void updateCatalogPromo(@NonNull NetworkPolicy policy, @Nullable MapObject mapObject) + { + if (mActivity == null) + throw new AssertionError("Activity must be non-null at this point!"); + + UiUtils.hide(mPlacePageView, R.id.catalog_promo_container); + + Sponsored sponsored = mPlacePageView.getSponsored(); + if (sponsored == null || mapObject == null) + return; + + PromoRequester requester = createPromoRequester(sponsored.getType()); + if (requester == null) + return; + + requester.requestPromo(policy, mapObject); + } + + @Override + public void attach(@NonNull Activity object) + { + mActivity = object; + Promo.INSTANCE.setListener(this); + } + + @Override + public void detach() + { + mActivity = null; + Promo.INSTANCE.setListener(null); + } + + @SuppressLint("SwitchIntDef") + @Nullable + private static PromoRequester createPromoRequester(@Sponsored.SponsoredType int type) + { + switch (type) + { + case Sponsored.TYPE_PROMO_CATALOG_POI: + return new PoiPromoRequester(); + case Sponsored.TYPE_PROMO_CATALOG_CITY: + return new CityPromoRequester(); + default: + return null; + } + } + + @Nullable + private PromoResponseHandler createPromoResponseHandler(@NonNull PromoCityGallery promo) + { + PromoCityGallery.Item[] items = promo.getItems(); + if (items.length <= 0) + return null; + + if (items.length == 1) + return new PoiPromoResponseHandler(); + + return new CityPromoResponseHandler(); + } + + interface PromoRequester + { + void requestPromo(@NonNull NetworkPolicy policy, @NonNull MapObject mapObject); + } + + static class PoiPromoRequester implements PromoRequester + { + @Override + public void requestPromo(@NonNull NetworkPolicy policy, @NonNull MapObject mapObject) + { + Promo.INSTANCE.nativeRequestPoiGallery(policy, mapObject.getLat(), mapObject.getLon(), + mapObject.getRawTypes(), UTM.UTM_SIGHTSEEINGS_PLACEPAGE_GALLERY); + } + } + + static class CityPromoRequester implements PromoRequester + { + @Override + public void requestPromo(@NonNull NetworkPolicy policy, @NonNull MapObject mapObject) + { + Promo.INSTANCE.nativeRequestCityGallery(policy, mapObject.getLat(), mapObject.getLon(), + UTM.UTM_LARGE_TOPONYMS_PLACEPAGE_GALLERY); + } + } + + interface PromoResponseHandler + { + void handleResponse(@NonNull PromoCityGallery promo); + } + + class PoiPromoResponseHandler implements PromoResponseHandler + { + @Override + public void handleResponse(@NonNull PromoCityGallery promo) + { + PromoCityGallery.Item[] items = promo.getItems(); + if (items.length <= 0) + return; + + UiUtils.show(mPlacePageView, R.id.catalog_promo_container, + R.id.promo_poi_description_container, R.id.promo_poi_description_divider, + R.id.promo_poi_card); + UiUtils.hide(mPromoRecycler); + mPromoTitle.setText(R.string.pp_discovery_place_related_header); + + PromoCityGallery.Item item = items[0]; + PromoCityGallery.Place place = item.getPlace(); + + TextView poiName = mPlacePageView.findViewById(R.id.promo_poi_name); + poiName.setText(place.getName()); + TextView poiDescription = mPlacePageView.findViewById(R.id.promo_poi_description); + poiDescription.setText(Html.fromHtml(place.getDescription())); + + ImageView poiImage = mPlacePageView.findViewById(R.id.promo_poi_image); + Glide.with(poiImage.getContext()) + .load(item.getImageUrl()) + .centerCrop() + .into(poiImage); + TextView bookmarkName = mPlacePageView.findViewById(R.id.place_single_bookmark_name); + bookmarkName.setText(item.getName()); + TextView authorName = mPlacePageView.findViewById(R.id.place_single_bookmark_author); + authorName.setText(item.getAuthor().getName()); + } + } + + class CityPromoResponseHandler implements PromoResponseHandler + { + @Override + public void handleResponse(@NonNull PromoCityGallery promo) + { + UiUtils.show(mPlacePageView, R.id.catalog_promo_container, + R.id.catalog_promo_title_divider, R.id.catalog_promo_recycler); + UiUtils.hide(mPlacePageView, R.id.promo_poi_description_container, + R.id.promo_poi_description_divider, R.id.promo_poi_card); + // TODO: we need to add additional field for title in server protocol (tag). + mPromoTitle.setText(R.string.guides); + String url = promo.getMoreUrl(); + RegularCatalogPromoListener promoListener = new RegularCatalogPromoListener(Objects.requireNonNull(mActivity), + GalleryPlacement.PLACEPAGE); + GalleryAdapter adapter = Factory.createCatalogPromoAdapter(mActivity, promo, url, + promoListener, + GalleryPlacement.PLACEPAGE); + mPromoRecycler.setAdapter(adapter); + } + } +} diff --git a/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java b/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java index b6b76dafa3..64fdf6848c 100644 --- a/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java +++ b/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java @@ -65,12 +65,9 @@ import com.mapswithme.maps.editor.data.Timetable; import com.mapswithme.maps.gallery.Constants; import com.mapswithme.maps.gallery.FullScreenGalleryActivity; import com.mapswithme.maps.gallery.GalleryActivity; -import com.mapswithme.maps.gallery.Items; -import com.mapswithme.maps.gallery.impl.Factory; -import com.mapswithme.maps.gallery.impl.RegularCatalogPromoListener; import com.mapswithme.maps.location.LocationHelper; import com.mapswithme.maps.metrics.UserActionsLogger; -import com.mapswithme.maps.promo.Promo; +import com.mapswithme.maps.promo.CatalogPromoController; import com.mapswithme.maps.promo.PromoCityGallery; import com.mapswithme.maps.promo.PromoEntity; import com.mapswithme.maps.review.Review; @@ -93,7 +90,6 @@ import com.mapswithme.util.NetworkPolicy; import com.mapswithme.util.SponsoredLinks; import com.mapswithme.util.StringUtils; import com.mapswithme.util.ThemeUtils; -import com.mapswithme.util.UTM; import com.mapswithme.util.UiUtils; import com.mapswithme.util.Utils; import com.mapswithme.util.concurrency.UiThread; @@ -101,8 +97,6 @@ import com.mapswithme.util.log.Logger; import com.mapswithme.util.log.LoggerFactory; import com.mapswithme.util.sharing.ShareOption; import com.mapswithme.util.statistics.AlohaHelper; -import com.mapswithme.util.statistics.GalleryPlacement; -import com.mapswithme.util.statistics.GalleryType; import com.mapswithme.util.statistics.Statistics; import java.util.ArrayList; @@ -131,8 +125,8 @@ public class PlacePageView extends NestedScrollView RecyclerClickListener, NearbyAdapter.OnItemClickListener, EditBookmarkFragment.EditBookmarkListener, - Detachable, - Promo.Listener + Detachable + { private static final Logger LOGGER = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.MISC); private static final String TAG = PlacePageView.class.getSimpleName(); @@ -229,6 +223,10 @@ public class PlacePageView extends NestedScrollView @NonNull private UGCController mUgcController; + @SuppressWarnings("NullableProblems") + @NonNull + private CatalogPromoController mCatalogPromoController; + // Data @Nullable private MapObject mMapObject; @@ -331,18 +329,10 @@ public class PlacePageView extends NestedScrollView @Nullable private RoutingModeListener mRoutingModeListener; - @SuppressWarnings("NullableProblems") - @NonNull - private RecyclerView mCatalogPromoRecycler; - @SuppressWarnings("NullableProblems") @NonNull private View mCatalogPromoTitleView; - @SuppressWarnings("NullableProblems") - @NonNull - private com.mapswithme.maps.gallery.GalleryAdapter mCatalogPromoLoadingAdapter; - void setScrollable(boolean scrollable) { mScrollable = scrollable; @@ -374,38 +364,13 @@ public class PlacePageView extends NestedScrollView @Override public void attach(@NonNull Activity object) { - Promo.INSTANCE.setListener(this); + mCatalogPromoController.attach(object); } @Override public void detach() { - Promo.INSTANCE.setListener(null); - } - - @Override - public void onCityGalleryReceived(@NonNull PromoCityGallery gallery) - { - String url = gallery.getMoreUrl(); - RegularCatalogPromoListener promoListener = new RegularCatalogPromoListener(getActivity(), - GalleryPlacement.PLACEPAGE); - com.mapswithme.maps.gallery.GalleryAdapter adapter = Factory.createCatalogPromoAdapter(getContext(), - gallery, - url, - promoListener, - GalleryPlacement.PLACEPAGE); - mCatalogPromoRecycler.setAdapter(adapter); - } - - @Override - public void onErrorReceived() - { - ErrorCatalogPromoListener listener = - new ErrorCatalogPromoListener<>(getActivity(), networkPolicy -> onNetworkPolicyResult(networkPolicy, mMapObject)); - com.mapswithme.maps.gallery.GalleryAdapter adapter = Factory.createCatalogPromoErrorAdapter(listener); - mCatalogPromoRecycler.setAdapter(adapter); - Statistics.INSTANCE.trackGalleryError(GalleryType.PROMO, GalleryPlacement.PLACEPAGE, - Statistics.ParamValue.NO_PRODUCTS); + mCatalogPromoController.detach(); } public interface SetMapObjectListener @@ -519,7 +484,8 @@ public class PlacePageView extends NestedScrollView initHotelGalleryView(); initHotelNearbyView(); initHotelRatingView(); - initCatalogPromoView(); + + mCatalogPromoController = new CatalogPromoController(this); mUgcController = new UGCController(this); @@ -874,23 +840,6 @@ public class PlacePageView extends NestedScrollView mRvHotelGallery.setAdapter(mGalleryAdapter); } - private void initCatalogPromoView() - { - mCatalogPromoRecycler = findViewById(R.id.catalog_promo_recycler); - mCatalogPromoTitleView = findViewById(R.id.catalog_promo_title); - mCatalogPromoLoadingAdapter = Factory.createCatalogPromoLoadingAdapter(); - mCatalogPromoRecycler.setNestedScrollingEnabled(false); - LinearLayoutManager layoutManager = new LinearLayoutManager(getContext(), - LinearLayoutManager.HORIZONTAL, - false); - mCatalogPromoRecycler.setLayoutManager(layoutManager); - RecyclerView.ItemDecoration decor = - ItemDecoratorFactory.createPlacePagePromoGalleryDecorator(getContext(), - LinearLayoutManager.HORIZONTAL); - mCatalogPromoRecycler.addItemDecoration(decor); - mCatalogPromoRecycler.setAdapter(mCatalogPromoLoadingAdapter); - } - private void initHotelFacilitiesView() { mHotelFacilities = findViewById(R.id.ll__place_hotel_facilities); @@ -1250,7 +1199,7 @@ public class PlacePageView extends NestedScrollView private void processSponsored(@NonNull NetworkPolicy policy) { - updateCatalogPromoGallery(policy); + mCatalogPromoController.updateCatalogPromo(policy, mMapObject); if (mSponsored == null || mMapObject == null) return; @@ -1269,41 +1218,6 @@ public class PlacePageView extends NestedScrollView Sponsored.requestInfo(mSponsored, Locale.getDefault().toString(), policy); } - private void updateCatalogPromoGallery(@NonNull NetworkPolicy policy) - { - boolean hasPromoGallery = mSponsored != null && mSponsored.getType() == Sponsored.TYPE_PROMO_CATALOG_CITY; - toggleCatalogPromoGallery(hasPromoGallery); - - if (mSponsored == null || mMapObject == null) - return; - - if (hasPromoGallery && policy.canUseNetwork()) - { - mCatalogPromoRecycler.setAdapter(mCatalogPromoLoadingAdapter); - // TODO: set correct UTM - Promo.INSTANCE.nativeRequestCityGallery(policy, mMapObject.getLat(), mMapObject.getLon(), - UTM.UTM_LARGE_TOPONYMS_PLACEPAGE_GALLERY); - } - else if (hasPromoGallery) - { - ErrorCatalogPromoListener listener = - new ErrorCatalogPromoListener<>(getActivity(), networkPolicy -> onNetworkPolicyResult(networkPolicy, mMapObject)); - com.mapswithme.maps.gallery.GalleryAdapter adapter = Factory.createCatalogPromoErrorAdapter(listener); - mCatalogPromoRecycler.setAdapter(adapter); - } - } - - private void onNetworkPolicyResult(@NonNull NetworkPolicy policy, @NonNull MapObject mapObject) - { - if (policy.canUseNetwork()) - { - // TODO: set correct UTM - Promo.INSTANCE.nativeRequestCityGallery(policy, mapObject.getLat(), mapObject.getLon(), - UTM.UTM_LARGE_TOPONYMS_PLACEPAGE_GALLERY); - mCatalogPromoRecycler.setAdapter(Factory.createCatalogPromoLoadingAdapter()); - } - } - private boolean isNetworkNeeded() { return mMapObject != null && (isSponsored() || mMapObject.getBanners() != null); @@ -1322,7 +1236,7 @@ public class PlacePageView extends NestedScrollView refreshHotelDetailViews(policy); refreshViewsInternal(mMapObject); mUgcController.getUGC(mMapObject); - updateCatalogPromoGallery(policy); + mCatalogPromoController.updateCatalogPromo(policy, mMapObject); } private void refreshViewsInternal(@NonNull MapObject mapObject)