package com.hannesdorfmann.mosby3.sample.mvi.view.search; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.transition.TransitionManager; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import butterknife.BindInt; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; import com.hannesdorfmann.mosby3.mvi.MviFragment; import com.hannesdorfmann.mosby3.sample.mvi.R; import com.hannesdorfmann.mosby3.sample.mvi.SampleApplication; import com.hannesdorfmann.mosby3.sample.mvi.businesslogic.interactor.search.SearchViewState; import com.hannesdorfmann.mosby3.sample.mvi.businesslogic.model.Product; import com.hannesdorfmann.mosby3.sample.mvi.view.detail.ProductDetailsActivity; import com.hannesdorfmann.mosby3.sample.mvi.view.ui.GridSpacingItemDecoration; import com.hannesdorfmann.mosby3.sample.mvi.view.ui.viewholder.ProductViewHolder; import com.jakewharton.rxbinding2.widget.RxSearchView; import io.reactivex.Observable; import java.util.List; import java.util.concurrent.TimeUnit; import timber.log.Timber; public class SearchFragment extends MviFragment<SearchView, SearchPresenter> implements SearchView, ProductViewHolder.ProductClickedListener { @BindView(R.id.searchView) android.widget.SearchView searchView; @BindView(R.id.container) ViewGroup container; @BindView(R.id.loadingView) View loadingView; @BindView(R.id.errorView) TextView errorView; @BindView(R.id.recyclerView) RecyclerView recyclerView; @BindView(R.id.emptyView) View emptyView; @BindInt(R.integer.grid_span_size) int spanCount; private SearchAdapter adapter; private Unbinder unbinder; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_search, container, false); unbinder = ButterKnife.bind(this, view); adapter = new SearchAdapter(inflater, this); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), spanCount)); recyclerView.addItemDecoration(new GridSpacingItemDecoration(spanCount, getResources().getDimensionPixelSize(R.dimen.grid_spacing), true)); return view; } @Override public void onDestroyView() { super.onDestroyView(); unbinder.unbind(); } @Override public void onProductClicked(Product product) { ProductDetailsActivity.start(getActivity(), product); } @NonNull @Override public SearchPresenter createPresenter() { Timber.d("createPresenter"); return SampleApplication.getDependencyInjection(getActivity()).newSearchPresenter(); } @Override public Observable<String> searchIntent() { return RxSearchView.queryTextChanges(searchView) .skip(2) // Because after screen orientation changes query Text will be resubmitted again .filter(queryString -> queryString.length() > 3 || queryString.length() == 0) .debounce(500, TimeUnit.MILLISECONDS) .distinctUntilChanged() .map(CharSequence::toString); } @Override public void render(SearchViewState viewState) { Timber.d("render %s", viewState); if (viewState instanceof SearchViewState.SearchNotStartedYet) { renderSearchNotStarted(); } else if (viewState instanceof SearchViewState.Loading) { renderLoading(); } else if (viewState instanceof SearchViewState.SearchResult) { renderResult(((SearchViewState.SearchResult) viewState).getResult()); } else if (viewState instanceof SearchViewState.EmptyResult) { renderEmptyResult(); } else if (viewState instanceof SearchViewState.Error) { Timber.e(((SearchViewState.Error) viewState).getError()); renderError(); } else { throw new IllegalArgumentException("Don't know how to render viewState " + viewState); } } private void renderResult(List<Product> result) { TransitionManager.beginDelayedTransition(container); recyclerView.setVisibility(View.VISIBLE); loadingView.setVisibility(View.GONE); emptyView.setVisibility(View.GONE); errorView.setVisibility(View.GONE); adapter.setProducts(result); adapter.notifyDataSetChanged(); } private void renderSearchNotStarted() { TransitionManager.beginDelayedTransition(container); recyclerView.setVisibility(View.GONE); loadingView.setVisibility(View.GONE); errorView.setVisibility(View.GONE); emptyView.setVisibility(View.GONE); } private void renderLoading() { TransitionManager.beginDelayedTransition(container); recyclerView.setVisibility(View.GONE); loadingView.setVisibility(View.VISIBLE); errorView.setVisibility(View.GONE); emptyView.setVisibility(View.GONE); } private void renderError() { TransitionManager.beginDelayedTransition(container); recyclerView.setVisibility(View.GONE); loadingView.setVisibility(View.GONE); errorView.setVisibility(View.VISIBLE); emptyView.setVisibility(View.GONE); } private void renderEmptyResult() { TransitionManager.beginDelayedTransition(container); recyclerView.setVisibility(View.GONE); loadingView.setVisibility(View.GONE); errorView.setVisibility(View.GONE); emptyView.setVisibility(View.VISIBLE); } }