[android] Implemented error/loading adapter strategies for search based galleries

This commit is contained in:
Александр Зацепин 2017-12-04 21:47:18 +03:00 committed by Ilya Grechuhin
parent bc55fd3d8e
commit ea18464cbd
17 changed files with 358 additions and 47 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/margin_quarter"
android:paddingStart="@dimen/margin_quarter"
android:paddingRight="@dimen/margin_half_plus"
android:paddingEnd="@dimen/margin_half_plus"
android:paddingTop="@dimen/margin_quarter"
android:paddingBottom="@dimen/margin_quarter"
android:clipToPadding="false">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/discovery_search_item_min_height"
android:orientation="vertical"
android:gravity="center_horizontal">
<ImageView
android:id="@+id/icon"
android:src="@drawable/ic_discovery_error"
android:layout_width="@dimen/margin_base_plus"
android:layout_height="@dimen/margin_base_plus"
android:layout_marginTop="@dimen/margin_double_plus"/>
<include layout="@layout/item_discovery_simple_message"/>
</LinearLayout>
</android.support.v7.widget.CardView>
</FrameLayout>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/margin_quarter"
android:paddingStart="@dimen/margin_quarter"
android:paddingRight="@dimen/margin_half_plus"
android:paddingEnd="@dimen/margin_half_plus"
android:paddingTop="@dimen/margin_quarter"
android:paddingBottom="@dimen/margin_quarter"
android:clipToPadding="false">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/discovery_search_item_min_height"
android:orientation="vertical"
android:gravity="center_horizontal">
<ProgressBar
android:id="@+id/progress"
android:layout_width="@dimen/margin_base_plus"
android:layout_height="@dimen/margin_base_plus"
android:layout_marginTop="@dimen/margin_double_plus"/>
<include layout="@layout/item_discovery_simple_message"/>
</LinearLayout>
</android.support.v7.widget.CardView>
</FrameLayout>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_base"
android:layout_marginLeft="@dimen/margin_half_plus"
android:layout_marginStart="@dimen/margin_half_plus"
android:layout_marginRight="@dimen/margin_half_plus"
android:layout_marginEnd="@dimen/margin_half_plus"
android:layout_marginBottom="@dimen/margin_double_and_half"
android:textAppearance="@style/MwmTextAppearance.Body3"
android:fontFamily="@string/robotoMedium"
android:maxLines="1"
android:ellipsize="end"
tools:targetApi="jelly_bean"
tools:showIn="@layout/item_discovery_simple_loading"/>

View file

@ -232,4 +232,5 @@
<!-- Discovery-->
<dimen name="discovery_button_min_height">40dp</dimen>
<dimen name="discovery_search_item_min_height">148dp</dimen>
</resources>

View file

@ -2,6 +2,7 @@ package com.mapswithme.maps.discovery;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -33,59 +34,50 @@ public class DiscoveryFragment extends BaseMwmToolbarFragment implements UICallb
DiscoveryParams.ITEM_TYPE_CAFES };
private static final GalleryAdapter.ItemSelectedListener LISTENER = new BaseItemSelectedListener();
private boolean mOnlineMode;
@SuppressWarnings("NullableProblems")
@NonNull
private RecyclerView mThingsToDo;
@SuppressWarnings("NullableProblems")
@NonNull
private RecyclerView mAttractions;
@SuppressWarnings("NullableProblems")
@NonNull
private RecyclerView mFood;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_discovery, container, false);
initViatorGallery(view);
initAttractionsGallery(view);
initFoodGallery(view);
return view;
return inflater.inflate(R.layout.fragment_discovery, container, false);
}
private void initViatorGallery(@NonNull View view)
private void initViatorGallery()
{
view.findViewById(R.id.viatorLogo).setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Utils.openUrl(getActivity(), DiscoveryManager.nativeGetViatorUrl());
}
});
mThingsToDo = (RecyclerView) view.findViewById(R.id.thingsToDo);
setLayoutManagerAndItemDecoration(getContext(), mThingsToDo);
setLayoutManagerAndItemDecoration(getContext(), getGallery(R.id.thingsToDo));
}
private void initAttractionsGallery(@NonNull View view)
private void initAttractionsGallery()
{
mAttractions = (RecyclerView) view.findViewById(R.id.attractions);
setLayoutManagerAndItemDecoration(getContext(), mAttractions);
setLayoutManagerAndItemDecoration(getContext(), getGallery(R.id.attractions));
}
private void initFoodGallery(@NonNull View view)
private void initFoodGallery()
{
mFood = (RecyclerView) view.findViewById(R.id.food);
setLayoutManagerAndItemDecoration(getContext(), mFood);
setLayoutManagerAndItemDecoration(getContext(), getGallery(R.id.food));
}
private static void setLayoutManagerAndItemDecoration(@NonNull Context context, @NonNull RecyclerView rv)
private static void setLayoutManagerAndItemDecoration(@NonNull Context context,
@NonNull RecyclerView rv)
{
rv.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL,false));
rv.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL,
false));
rv.addItemDecoration(
ItemDecoratorFactory.createSponsoredGalleryDecorator(context, LinearLayoutManager.HORIZONTAL));
ItemDecoratorFactory.createSponsoredGalleryDecorator(context,
LinearLayoutManager.HORIZONTAL));
}
@NonNull
private RecyclerView getGallery(@IdRes int id)
{
View view = getView();
if (view == null)
throw new AssertionError("Root view is not initialized yet!");
RecyclerView rv = (RecyclerView) view.findViewById(id);
if (rv == null)
throw new AssertionError("RecyclerView must be within root view!");
return rv;
}
@Override
@ -107,11 +99,24 @@ public class DiscoveryFragment extends BaseMwmToolbarFragment implements UICallb
{
super.onViewCreated(view, savedInstanceState);
mToolbarController.setTitle(R.string.discovery_button_title);
view.findViewById(R.id.viatorLogo).setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Utils.openUrl(getActivity(), DiscoveryManager.nativeGetViatorUrl());
}
});
initViatorGallery();
initAttractionsGallery();
initFoodGallery();
requestDiscoveryInfoAndInitAdapters();
}
private void requestDiscoveryInfoAndInitAdapters()
{
initSearchBasedAdapters();
NetworkPolicy.checkNetworkPolicy(getFragmentManager(), new NetworkPolicy.NetworkPolicyListener()
{
@Override
@ -124,12 +129,19 @@ public class DiscoveryFragment extends BaseMwmToolbarFragment implements UICallb
});
}
private void initSearchBasedAdapters()
{
getGallery(R.id.attractions).setAdapter(Factory.createSearchBasedLoadingAdapter());
getGallery(R.id.food).setAdapter(Factory.createSearchBasedLoadingAdapter());
}
private void initNetworkBasedAdapters()
{
if (mOnlineMode)
{
// TODO: set loading adapter for local experts here.
mThingsToDo.setAdapter(Factory.createViatorLoadingAdapter(DiscoveryManager.nativeGetViatorUrl(),
RecyclerView thinsToDo = getGallery(R.id.thingsToDo);
thinsToDo.setAdapter(Factory.createViatorLoadingAdapter(DiscoveryManager.nativeGetViatorUrl(),
LISTENER));
return;
}
@ -144,7 +156,8 @@ public class DiscoveryFragment extends BaseMwmToolbarFragment implements UICallb
else
{
UiUtils.show(getView(), R.id.thingsToDoLayout, R.id.thingsToDo);
mThingsToDo.setAdapter(Factory.createViatorOfflineAdapter(new ViatorOfflineSelectedListener()));
RecyclerView thinsToDo = getGallery(R.id.thingsToDo);
thinsToDo.setAdapter(Factory.createViatorOfflineAdapter(new ViatorOfflineSelectedListener()));
}
}
@ -172,7 +185,7 @@ public class DiscoveryFragment extends BaseMwmToolbarFragment implements UICallb
if (results == null)
return;
mAttractions.setAdapter(Factory.createSearchBasedAdapter(results, LISTENER));
getGallery(R.id.attractions).setAdapter(Factory.createSearchBasedAdapter(results, LISTENER));
}
@MainThread
@ -182,7 +195,7 @@ public class DiscoveryFragment extends BaseMwmToolbarFragment implements UICallb
if (results == null)
return;
mFood.setAdapter(Factory.createSearchBasedAdapter(results, LISTENER));
getGallery(R.id.food).setAdapter(Factory.createSearchBasedAdapter(results, LISTENER));
}
@MainThread
@ -192,8 +205,8 @@ public class DiscoveryFragment extends BaseMwmToolbarFragment implements UICallb
if (products == null)
return;
mThingsToDo.setAdapter(Factory.createViatorAdapter(products, DiscoveryManager.nativeGetViatorUrl(),
LISTENER));
String url = DiscoveryManager.nativeGetViatorUrl();
getGallery(R.id.thingsToDo).setAdapter(Factory.createViatorAdapter(products, url, LISTENER));
}
@MainThread
@ -209,11 +222,20 @@ public class DiscoveryFragment extends BaseMwmToolbarFragment implements UICallb
switch (type)
{
case VIATOR:
mThingsToDo.setAdapter(Factory.createViatorErrorAdapter(DiscoveryManager.nativeGetViatorUrl(),
LISTENER));
String url = DiscoveryManager.nativeGetViatorUrl();
getGallery(R.id.thingsToDo).setAdapter(Factory.createViatorErrorAdapter(url, LISTENER));
break;
// TODO: processing for other adapters is coming soon.
case ATTRACTIONS:
getGallery(R.id.attractions).setAdapter(Factory.createSearchBasedErrorAdapter());
break;
case CAFES:
getGallery(R.id.food).setAdapter(Factory.createSearchBasedErrorAdapter());
break;
case LOCAL_EXPERTS:
//TODO: coming soon.
break;
default:
throw new AssertionError("Unknown item type: " + type);
}
}

View file

@ -154,7 +154,8 @@ public class Holders
@NonNull
private final TextView mButton;
public SearchViewHolder(@NonNull View itemView, @NonNull List<Items.SearchItem> items, @NonNull GalleryAdapter adapter)
public SearchViewHolder(@NonNull View itemView, @NonNull List<Items.SearchItem> items,
@NonNull GalleryAdapter adapter)
{
super(itemView, items, adapter);
mTitle = (TextView) itemView.findViewById(R.id.title);
@ -261,6 +262,16 @@ public class Holders
}
}
public static class SimpleViewHolder extends BaseViewHolder<Items.Item>
{
public SimpleViewHolder(@NonNull View itemView, @NonNull List<Items.Item> items,
@NonNull GalleryAdapter adapter)
{
super(itemView, items, adapter);
mTitle = (TextView) itemView.findViewById(R.id.message);
}
}
static class ErrorViewHolder extends LoadingViewHolder
{

View file

@ -0,0 +1,47 @@
package com.mapswithme.maps.gallery;
import android.content.res.Resources;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.mapswithme.maps.MwmApplication;
public abstract class SimpleSingleItemAdapterStrategy<T extends Holders.BaseViewHolder<Items.Item>>
extends SingleItemAdapterStrategy<T>
{
protected SimpleSingleItemAdapterStrategy()
{
super(null);
}
@Override
protected void buildItem(@Nullable String url)
{
Resources res = MwmApplication.get().getResources();
mItems.add(new Items.Item(res.getString(getTitle()), null, null));
}
@NonNull
@Override
protected T createViewHolder(@NonNull ViewGroup parent, int viewType,
@NonNull GalleryAdapter adapter)
{
View itemView = inflateView(LayoutInflater.from(parent.getContext()), parent);
return createViewHolder(itemView, adapter);
}
@Override
protected final int getSubtitle()
{
throw new UnsupportedOperationException("Subtitle is not supported by this strategy!");
}
@Override
protected final int getLabelForDetailsView()
{
throw new UnsupportedOperationException("Details button is not supported by this strategy!");
}
}

View file

@ -16,6 +16,11 @@ abstract class SingleItemAdapterStrategy<T extends Holders.BaseViewHolder<Items.
extends AdapterStrategy<T, Items.Item>
{
SingleItemAdapterStrategy(@Nullable String url)
{
buildItem(url);
}
protected void buildItem(@Nullable String url)
{
Resources res = MwmApplication.get().getResources();
mItems.add(new Items.Item(res.getString(getTitle()), url,
@ -35,7 +40,7 @@ abstract class SingleItemAdapterStrategy<T extends Holders.BaseViewHolder<Items.
@NonNull
@Override
protected T createViewHolder(@NonNull ViewGroup parent, int viewType,
@NonNull GalleryAdapter adapter)
@NonNull GalleryAdapter adapter)
{
View itemView = inflateView(LayoutInflater.from(parent.getContext()), parent);
TextView button = (TextView) itemView.findViewById(R.id.button);

View file

@ -65,4 +65,16 @@ public class Factory
{
return new GalleryAdapter<>(new SearchBasedAdapterStrategy(results), listener);
}
@NonNull
public static GalleryAdapter createSearchBasedLoadingAdapter()
{
return new GalleryAdapter<>(new SimpleLoadingAdapterStrategy(), null);
}
@NonNull
public static GalleryAdapter createSearchBasedErrorAdapter()
{
return new GalleryAdapter<>(new SimpleErrorAdapterStrategy(), null);
}
}

View file

@ -0,0 +1,63 @@
package com.mapswithme.maps.gallery.impl;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.mapswithme.maps.R;
import com.mapswithme.maps.gallery.GalleryAdapter;
import com.mapswithme.maps.gallery.Holders;
import com.mapswithme.maps.gallery.Items;
import com.mapswithme.maps.gallery.RegularAdapterStrategy;
import com.mapswithme.maps.search.SearchResult;
import java.util.ArrayList;
import java.util.List;
class SearchBasedAdapterStrategy extends RegularAdapterStrategy<Items.SearchItem>
{
SearchBasedAdapterStrategy(@NonNull SearchResult[] results)
{
this(convertItems(results), null);
}
private SearchBasedAdapterStrategy(@NonNull List<Items.SearchItem> items,
@Nullable Items.SearchItem moreItem)
{
super(items, moreItem);
}
@NonNull
@Override
protected Holders.BaseViewHolder<Items.SearchItem> createProductViewHodler(@NonNull ViewGroup parent,
int viewType,
@NonNull GalleryAdapter adapter)
{
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_discovery_search, parent, false);
return new Holders.SearchViewHolder(view, mItems, adapter);
}
@NonNull
@Override
protected final Holders.BaseViewHolder<Items.SearchItem> createMoreProductsViewHolder(@NonNull ViewGroup parent,
int viewType,
@NonNull GalleryAdapter adapter)
{
throw new UnsupportedOperationException("More item is not supported yet for this strategy!");
}
@NonNull
private static List<Items.SearchItem> convertItems(@NonNull SearchResult[] results)
{
List<Items.SearchItem> viewItems = new ArrayList<>();
for (SearchResult result : results)
{
SearchResult.Description d = result.description;
viewItems.add(new Items.SearchItem(result.name, null, d.featureType, d.distance));
}
return viewItems;
}
}

View file

@ -0,0 +1,35 @@
package com.mapswithme.maps.gallery.impl;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.mapswithme.maps.R;
import com.mapswithme.maps.gallery.GalleryAdapter;
import com.mapswithme.maps.gallery.Holders;
import com.mapswithme.maps.gallery.SimpleSingleItemAdapterStrategy;
public class SimpleErrorAdapterStrategy
extends SimpleSingleItemAdapterStrategy<Holders.SimpleViewHolder>
{
@Override
protected int getTitle()
{
return R.string.discovery_button_other_error_message;
}
@NonNull
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent)
{
return inflater.inflate(R.layout.item_discovery_simple_error, parent, false);
}
@Override
protected Holders.SimpleViewHolder createViewHolder(@NonNull View itemView,
@NonNull GalleryAdapter adapter)
{
return new Holders.SimpleViewHolder(itemView, mItems, adapter);
}
}

View file

@ -0,0 +1,35 @@
package com.mapswithme.maps.gallery.impl;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.mapswithme.maps.R;
import com.mapswithme.maps.gallery.GalleryAdapter;
import com.mapswithme.maps.gallery.Holders;
import com.mapswithme.maps.gallery.SimpleSingleItemAdapterStrategy;
public class SimpleLoadingAdapterStrategy
extends SimpleSingleItemAdapterStrategy<Holders.SimpleViewHolder>
{
@Override
protected int getTitle()
{
return R.string.discovery_button_other_loading_message;
}
@NonNull
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent)
{
return inflater.inflate(R.layout.item_discovery_simple_loading, parent, false);
}
@Override
protected Holders.SimpleViewHolder createViewHolder(@NonNull View itemView,
@NonNull GalleryAdapter adapter)
{
return new Holders.SimpleViewHolder(itemView, mItems, adapter);
}
}