[android] Customized the promo category for search to make it reusable for different promo actions and providers

This commit is contained in:
Александр Зацепин 2018-10-17 17:41:40 +03:00 committed by Roman Kuznetsov
parent c294eca849
commit 658a8e26aa
9 changed files with 189 additions and 82 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -2,6 +2,7 @@ package com.mapswithme.maps.search;
import android.content.res.Resources;
import android.support.annotation.DrawableRes;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
@ -16,8 +17,17 @@ import com.mapswithme.maps.R;
import com.mapswithme.util.ThemeUtils;
import com.mapswithme.util.statistics.Statistics;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
class CategoriesAdapter extends RecyclerView.Adapter<CategoriesAdapter.ViewHolder>
{
@Retention(RetentionPolicy.SOURCE)
@IntDef({ TYPE_CATEGORY, TYPE_PROMO_CATEGORY })
@interface ViewType {}
private static final int TYPE_CATEGORY = 0;
private static final int TYPE_PROMO_CATEGORY = 1;
@StringRes
private final int mCategoryResIds[];
@DrawableRes
@ -28,18 +38,19 @@ class CategoriesAdapter extends RecyclerView.Adapter<CategoriesAdapter.ViewHolde
interface OnCategorySelectedListener
{
void onCategorySelected(@Nullable String category);
void onSearchCategorySelected(@Nullable String category);
void onPromoCategorySelected(@NonNull PromoCategory promo);
}
private OnCategorySelectedListener mListener;
CategoriesAdapter(Fragment fragment)
CategoriesAdapter(@NonNull Fragment fragment)
{
final String packageName = fragment.getActivity().getPackageName();
final boolean isNightTheme = ThemeUtils.isNightTheme();
final Resources resources = fragment.getActivity().getResources();
final String[] keys = DisplayedCategories.getKeys();
final String[] keys = getAllCategories();
final int numKeys = keys.length;
mCategoryResIds = new int[numKeys];
@ -47,16 +58,7 @@ class CategoriesAdapter extends RecyclerView.Adapter<CategoriesAdapter.ViewHolde
for (int i = 0; i < numKeys; i++)
{
String key = keys[i];
mCategoryResIds[i] = resources.getIdentifier(key, "string", packageName);
PromoCategory promo = PromoCategory.findByKey(key);
if (promo != null)
{
Statistics.INSTANCE.trackSponsoredEventForCustomProvider(
Statistics.EventName.SEARCH_SPONSOR_CATEGORY_SHOWN,
promo.getStatisticValue());
mCategoryResIds[i] = promo.getStringId();
}
if (mCategoryResIds[i] == 0)
throw new IllegalStateException("Can't get string resource id for category:" + key);
@ -75,24 +77,58 @@ class CategoriesAdapter extends RecyclerView.Adapter<CategoriesAdapter.ViewHolde
mInflater = LayoutInflater.from(fragment.getActivity());
}
@Override
public int getItemViewType(int position)
@NonNull
private static String[] getAllCategories()
{
return R.layout.item_search_category;
String[] searchCategories = DisplayedCategories.getKeys();
PromoCategory[] promos = PromoCategory.values();
int amountSize = searchCategories.length + promos.length;
String[] allCategories = new String[amountSize];
for (PromoCategory promo : promos)
{
if (promo.getPosition() >= amountSize)
throw new AssertionError("Promo position must in range: "
+ "[0 - " + amountSize + ")");
allCategories[promo.getPosition()] = promo.getKey();
}
for (int i = 0, j = 0; i < amountSize; i++)
{
if (allCategories[i] == null)
{
allCategories[i] = searchCategories[j];
j++;
}
}
return allCategories;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
@ViewType
public int getItemViewType(int position)
{
PromoCategory promo = PromoCategory.findByStringId(mCategoryResIds[position]);
if (promo != null)
return TYPE_PROMO_CATEGORY;
return TYPE_CATEGORY;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, @ViewType int viewType)
{
final View view;
if (viewType == R.layout.item_search_category_luggage)
{
view = mInflater.inflate(R.layout.item_search_category_luggage, parent, false);
return new ViewHolder(view, (TextView) view.findViewById(R.id.tv__category));
}
view = mInflater.inflate(R.layout.item_search_category, parent, false);
return new ViewHolder(view, (TextView)view);
switch (viewType)
{
case TYPE_CATEGORY:
return new ViewHolder(view, (TextView) view);
case TYPE_PROMO_CATEGORY:
return new PromoViewHolder(view, (TextView) view);
default:
throw new AssertionError("Unsupported type detected: " + viewType);
}
}
@Override
@ -107,16 +143,44 @@ class CategoriesAdapter extends RecyclerView.Adapter<CategoriesAdapter.ViewHolde
return mCategoryResIds.length;
}
@NonNull
private String getSuggestionFromCategory(@StringRes int resId)
private class PromoViewHolder extends ViewHolder
{
PromoCategory promoCategory = PromoCategory.findByStringId(resId);
if (promoCategory != null)
return promoCategory.getKey();
return mResources.getString(resId) + ' ';
PromoViewHolder(@NonNull View v, @NonNull TextView tv)
{
super(v, tv);
}
@Override
void onItemClicked(int position)
{
@StringRes
int categoryId = mCategoryResIds[position];
PromoCategory promo = PromoCategory.findByStringId(categoryId);
if (promo != null)
{
String event = Statistics.EventName.SEARCH_SPONSOR_CATEGORY_SELECTED;
Statistics.INSTANCE.trackSearchPromoCategory(event, promo.getProvider());
if (mListener != null)
mListener.onPromoCategorySelected(promo);
}
}
@Override
void setTextAndIcon(int textResId, int iconResId)
{
super.setTextAndIcon(textResId, iconResId);
@StringRes
int categoryId = mCategoryResIds[getAdapterPosition()];
PromoCategory promo = PromoCategory.findByStringId(categoryId);
if (promo != null)
{
String event = Statistics.EventName.SEARCH_SPONSOR_CATEGORY_SHOWN;
Statistics.INSTANCE.trackSearchPromoCategory(event, promo.getProvider());
}
}
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
@NonNull
private final TextView mTitle;
@ -129,12 +193,22 @@ class CategoriesAdapter extends RecyclerView.Adapter<CategoriesAdapter.ViewHolde
}
@Override
public void onClick(View v)
public final void onClick(View v)
{
final int position = getAdapterPosition();
Statistics.INSTANCE.trackSearchCategoryClicked(mResources.getResourceEntryName(mCategoryResIds[position]));
onItemClicked(position);
}
void onItemClicked(int position)
{
String categoryEntryName = mResources.getResourceEntryName(mCategoryResIds[position]);
Statistics.INSTANCE.trackSearchCategoryClicked(categoryEntryName);
if (mListener != null)
mListener.onCategorySelected(getSuggestionFromCategory(mCategoryResIds[position]));
{
@StringRes
int categoryId = mCategoryResIds[position];
mListener.onSearchCategorySelected(mResources.getString(categoryId) + " ");
}
}
void setTextAndIcon(@StringRes int textResId, @DrawableRes int iconResId)

View file

@ -1,8 +1,15 @@
package com.mapswithme.maps.search;
import android.support.annotation.NonNull;
class DisplayedCategories
{
public static String[] getKeys() { return nativeGetKeys(); }
@NonNull
public static String[] getKeys()
{
return nativeGetKeys();
}
@NonNull
private static native String[] nativeGetKeys();
}

View file

@ -1,34 +1,47 @@
package com.mapswithme.maps.search;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.text.TextUtils;
import com.mapswithme.util.UiUtils;
import com.mapswithme.maps.R;
public enum PromoCategory
{
STUB
RUTAXI
{
@NonNull
@Override
String getKey()
{
return "";
return "taxi";
}
@Override
int getStringId()
{
return UiUtils.NO_ID;
return R.string.taxi;
}
@NonNull
@Override
String getStatisticValue()
String getProvider()
{
return "";
return "RuTaxi";
}
@Override
int getPosition()
{
return 4;
}
@NonNull
@Override
PromoCategoryProcessor createProcessor(@NonNull Context context)
{
return new RutaxiPromoProcessor(context);
}
};
@ -39,7 +52,12 @@ public enum PromoCategory
abstract int getStringId();
@NonNull
abstract String getStatisticValue();
abstract String getProvider();
abstract int getPosition();
@NonNull
abstract PromoCategoryProcessor createProcessor(@NonNull Context context);
@Nullable
static PromoCategory findByStringId(@StringRes int nameId)
@ -51,18 +69,4 @@ public enum PromoCategory
}
return null;
}
@Nullable
static PromoCategory findByKey(@Nullable String key)
{
if (TextUtils.isEmpty(key))
return null;
for (PromoCategory cat : values())
{
if (cat.getKey().equals(key))
return cat;
}
return null;
}
}

View file

@ -0,0 +1,6 @@
package com.mapswithme.maps.search;
public interface PromoCategoryProcessor
{
void process();
}

View file

@ -0,0 +1,24 @@
package com.mapswithme.maps.search;
import android.content.Context;
import android.support.annotation.NonNull;
import com.mapswithme.util.Utils;
public class RutaxiPromoProcessor implements PromoCategoryProcessor
{
@NonNull
private final Context mContext;
RutaxiPromoProcessor(@NonNull Context context)
{
mContext = context;
}
@Override
public void process()
{
// TODO: added app launch when product desicion is ready.
Utils.openUrl(mContext, "https://go.onelink.me/757212956/a81b5d7c");
}
}

View file

@ -3,7 +3,6 @@ package com.mapswithme.maps.search;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import com.mapswithme.maps.R;
import com.mapswithme.maps.base.BaseMwmRecyclerFragment;
@ -31,18 +30,25 @@ public class SearchCategoriesFragment extends BaseMwmRecyclerFragment<Categories
}
@Override
public void onCategorySelected(String category)
public void onSearchCategorySelected(String category)
{
if (!passCategory(getParentFragment(), category))
passCategory(getActivity(), category);
}
@Override
public void onPromoCategorySelected(@NonNull PromoCategory promo)
{
PromoCategoryProcessor processor = promo.createProcessor(getContext().getApplicationContext());
processor.process();
}
private static boolean passCategory(Object listener, String category)
{
if (!(listener instanceof CategoriesAdapter.OnCategorySelectedListener))
return false;
((CategoriesAdapter.OnCategorySelectedListener)listener).onCategorySelected(category);
((CategoriesAdapter.OnCategorySelectedListener)listener).onSearchCategorySelected(category);
return true;
}
}

View file

@ -129,9 +129,6 @@ public class SearchFragment extends BaseMwmFragment
return;
}
if (mPromoCategorySelected)
return;
if (mAdsLoader != null && !isTabletSearch() && query.length() >= MIN_QUERY_LENGTH_FOR_AD)
{
mAdsRequested = true;
@ -211,7 +208,6 @@ public class SearchFragment extends BaseMwmFragment
private final LastPosition mLastPosition = new LastPosition();
private boolean mSearchRunning;
private boolean mPromoCategorySelected;
private String mInitialQuery;
@Nullable
private String mInitialLocale;
@ -710,24 +706,15 @@ public class SearchFragment extends BaseMwmFragment
}
@Override
public void onCategorySelected(@Nullable String category)
public void onSearchCategorySelected(@Nullable String category)
{
PromoCategory promoCategory = PromoCategory.findByKey(category);
if (promoCategory != null)
{
mPromoCategorySelected = true;
mToolbarController.setQuery(category + " ");
mToolbarController.setQuery(category);
}
Statistics.INSTANCE.trackSponsoredEventForCustomProvider(
Statistics.EventName.SEARCH_SPONSOR_CATEGORY_SELECTED,
promoCategory.getStatisticValue());
showAllResultsOnMap();
mPromoCategorySelected = false;
}
else
{
mToolbarController.setQuery(category);
}
@Override
public void onPromoCategorySelected(@NonNull PromoCategory promo)
{
// Do nothing by default.
}
private void refreshSearchResults()

View file

@ -16,12 +16,12 @@ import com.android.billingclient.api.BillingClient;
import com.facebook.ads.AdError;
import com.facebook.appevents.AppEventsLogger;
import com.mapswithme.maps.BuildConfig;
import com.mapswithme.maps.analytics.ExternalLibrariesMediator;
import com.mapswithme.maps.Framework;
import com.mapswithme.maps.MwmApplication;
import com.mapswithme.maps.PrivateVariables;
import com.mapswithme.maps.ads.MwmNativeAd;
import com.mapswithme.maps.ads.NativeAdError;
import com.mapswithme.maps.analytics.ExternalLibrariesMediator;
import com.mapswithme.maps.api.ParsedMwmRequest;
import com.mapswithme.maps.bookmarks.data.BookmarkManager;
import com.mapswithme.maps.bookmarks.data.MapObject;
@ -955,8 +955,7 @@ public enum Statistics
.get());
}
public void trackSponsoredEventForCustomProvider(@NonNull String eventName,
@NonNull String provider)
public void trackSearchPromoCategory(@NonNull String eventName, @NonNull String provider)
{
trackEvent(eventName, Statistics.params().add(PROVIDER, provider).get());
MyTracker.trackEvent(eventName + "_" + provider);