com.hybris.mobile.app.commerce.fragment.CatalogContentFragmentBase.java Source code

Java tutorial

Introduction

Here is the source code for com.hybris.mobile.app.commerce.fragment.CatalogContentFragmentBase.java

Source

/*******************************************************************************
 * [y] hybris Platform
 *
 * Copyright (c) 2000-2015 hybris AG
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of hybris
 * ("Confidential Information"). You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the
 * license agreement you entered into with hybris.
 ******************************************************************************/
package com.hybris.mobile.app.commerce.fragment;

import android.app.Activity;
import android.app.Fragment;
import android.app.SearchManager;
import android.content.Intent;
import android.content.res.Configuration;
import android.database.Cursor;
import android.database.MergeCursor;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.CursorAdapter;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;

import com.hybris.mobile.app.commerce.CommerceApplication;
import com.hybris.mobile.app.commerce.R;
import com.hybris.mobile.app.commerce.adapter.ProductGridAdapter;
import com.hybris.mobile.app.commerce.adapter.ProductListAdapter;
import com.hybris.mobile.app.commerce.adapter.ViewTypeAdapter;
import com.hybris.mobile.app.commerce.helper.SessionHelper;
import com.hybris.mobile.app.commerce.utils.UIUtils;
import com.hybris.mobile.app.commerce.view.ViewTypeItem;
import com.hybris.mobile.lib.commerce.data.catalog.CategoryHierarchy;
import com.hybris.mobile.lib.commerce.data.error.ErrorList;
import com.hybris.mobile.lib.commerce.data.search.facetdata.SpellingSuggestion;
import com.hybris.mobile.lib.commerce.data.search.pagedata.Pagination;
import com.hybris.mobile.lib.commerce.loader.ProductListLoader;
import com.hybris.mobile.lib.commerce.provider.CatalogContract;
import com.hybris.mobile.lib.commerce.provider.CatalogContract.DataBaseDataSimple;
import com.hybris.mobile.lib.commerce.provider.CatalogDatabaseHelper;
import com.hybris.mobile.lib.commerce.query.QueryProducts;
import com.hybris.mobile.lib.http.listener.OnRequestListener;
import com.hybris.mobile.lib.http.response.Response;
import com.hybris.mobile.lib.http.utils.RequestUtils;
import com.hybris.mobile.lib.ui.listener.InfiniteScrollListener;

import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * Fragment to display the list of product
 */
public abstract class CatalogContentFragmentBase extends Fragment {
    protected static final String SAVED_INSTANCE_CATEGORY = "SAVED_INSTANCE_CATEGORY";
    protected static final String SAVED_INSTANCE_SEARCH_TEXT = "SAVED_INSTANCE_SEARCH_TEXT";
    protected static final String TAG = CatalogContentFragmentBase.class.getCanonicalName();
    protected String mSearchRequestId = RequestUtils.generateUniqueRequestId();
    protected OnSearchRequestListener mActivity;
    protected CategoryHierarchy mCurrentCategory;
    protected String mCurrentSearchText;
    /**
     * Onclick listener for did you mean text
     */
    protected OnClickListener mDidYouMeanOnClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            resetData();
            mCurrentSearchText = ((TextView) v).getText().toString();

            // Updating product list
            updateProductList();
        }
    };
    protected int mCurrentPage;
    protected TextView mCategoryBreadcrumb;
    protected View mSearchHeader;
    protected View mSearchHeaderDidYouMeanView;
    protected TextView mSearchHeaderSearched;
    protected TextView mSearchHeaderDidYouMean;
    protected TextView mSearchHeaderNbResults;
    protected View mNoProductFoundView;
    protected View mNoProductFoundViewImage;
    protected View mNoProductFoundDidYouMeanView;
    protected TextView mNoProductFoundTextView;
    protected TextView mNoProductFoundDidYouMeanTextView;
    protected InfiniteScrollListener mInfiniteScrollListener;
    protected View mFooterLoadingListView;
    protected Spinner mItemViewTypeSpinner;
    protected ListView mProductListView;
    protected CursorAdapter mProductItemsAdapter;
    protected GridView mProductGridView;
    protected ProductListLoader mProductListLoader;
    protected boolean mInitialCall;
    protected boolean mOnCategorySelectedActivated = true;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // Make sure that the activity implements the callback interface
        try {
            mActivity = (OnSearchRequestListener) activity;
        } catch (ClassCastException e) {
            Log.e(TAG, e.getLocalizedMessage());
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mActivity = null;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_catalog_content, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // Breadcrum
        mCategoryBreadcrumb = (TextView) getView().findViewById(R.id.catalog_content_header_breadcumb);
        mCategoryBreadcrumb.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // Open the drawer
                DrawerLayout mCatalogDrawer = ((DrawerLayout) getActivity().findViewById(R.id.catalog_menu_drawer));
                mCatalogDrawer.openDrawer(mCatalogDrawer.getChildAt(1));
            }
        });

        List<ViewTypeItem> viewTypeTextViewList = new ArrayList<>();
        viewTypeTextViewList.add(new ViewTypeItem(getString(R.string.catalog_content_header_list_view),
                R.drawable.ic_subnav_list_blue));
        viewTypeTextViewList.add(new ViewTypeItem(getString(R.string.catalog_content_header_grid_view),
                R.drawable.ic_subnav_grid_blue));
        mItemViewTypeSpinner = (Spinner) getView().findViewById(R.id.catalog_content_header_view_type_spinner);
        ViewTypeAdapter mViewTypeAdapter = new ViewTypeAdapter(getActivity(), viewTypeTextViewList);
        mItemViewTypeSpinner.setAdapter(mViewTypeAdapter);
        mItemViewTypeSpinner.setOnItemSelectedListener(new ItemViewTypeSpinnerListener());

        // Select the default view
        mItemViewTypeSpinner.setSelection(SessionHelper.getCatalogContentViewType());

        // List/Line view
        mProductListView = (ListView) getView().findViewById(R.id.catalog_content_product_list);

        // Footer loading
        mFooterLoadingListView = getActivity().getLayoutInflater().inflate(R.layout.loading_spinner,
                mProductListView, false);

        // Grid view
        mProductGridView = (GridView) getView().findViewById(R.id.catalog_content_product_grid);

        // Infinite scroll listener for the list view
        mInfiniteScrollListener = new InfiniteScrollListener() {

            @Override
            public void loadNextItems(int page) {
                Log.i(TAG, "Loading the items for page " + page);
                mCurrentPage = page;
                updateProductList();
            }

        };

        mProductListView.setOnScrollListener(mInfiniteScrollListener);
        mProductGridView.setOnScrollListener(mInfiniteScrollListener);

        // Default product adapter
        mProductItemsAdapter = new ProductListAdapter(getActivity(), null, 0,
                CommerceApplication.getContentServiceHelper());

        // No product found view
        mNoProductFoundView = getActivity().findViewById(R.id.catalog_content_product_list_no_product_found);
        mNoProductFoundTextView = (TextView) getActivity()
                .findViewById(R.id.catalog_content_product_list_no_product_found_text);
        mNoProductFoundViewImage = getActivity()
                .findViewById(R.id.catalog_content_product_list_no_product_found_image);
        mNoProductFoundDidYouMeanView = getActivity()
                .findViewById(R.id.catalog_content_product_list_no_product_found_did_you_mean_view);
        mNoProductFoundDidYouMeanTextView = (TextView) getActivity()
                .findViewById(R.id.catalog_content_product_list_no_product_found_did_you_mean);

        // On click on did you mean, we update the list with the suggested term
        mNoProductFoundDidYouMeanTextView.setOnClickListener(mDidYouMeanOnClickListener);

        // Search header
        mSearchHeader = getActivity().findViewById(R.id.catalog_content_product_list_header_search);
        mSearchHeaderSearched = (TextView) getActivity()
                .findViewById(R.id.catalog_content_product_list_header_search_searched);
        mSearchHeaderDidYouMean = (TextView) getActivity()
                .findViewById(R.id.catalog_content_product_list_header_search_did_you_mean);
        mSearchHeaderDidYouMeanView = getActivity()
                .findViewById(R.id.catalog_content_product_list_header_search_did_you_mean_view);
        mSearchHeaderNbResults = (TextView) getActivity()
                .findViewById(R.id.catalog_content_product_list_header_search_nb_results);

        // On click on did you mean, we update the list with the suggested term
        mSearchHeaderDidYouMean.setOnClickListener(mDidYouMeanOnClickListener);

        // Restore the current category or search query
        if (savedInstanceState != null) {
            if (savedInstanceState.containsKey(SAVED_INSTANCE_CATEGORY)) {
                mCurrentCategory = savedInstanceState.getParcelable(SAVED_INSTANCE_CATEGORY);
            }

            if (savedInstanceState.containsKey(SAVED_INSTANCE_SEARCH_TEXT)) {
                mCurrentSearchText = savedInstanceState.getString(SAVED_INSTANCE_SEARCH_TEXT);
            }

        }

        // Product list loader
        mProductListLoader = new ProductListLoader(getActivity(), CommerceApplication.getContentServiceHelper(),
                mProductItemsAdapter, new QueryProducts(), new OnRequestListener() {

                    @Override
                    public void beforeRequest() {
                        showLoading(true);
                    }

                    @Override
                    public void afterRequestBeforeResponse() {

                    }

                    @Override
                    public void afterRequest(boolean isDataSynced) {
                        updateUI(false, null, mProductItemsAdapter.getCount());
                        mInitialCall = false;

                        // TODO - offline enabling this will cause the content provider provider to ba called infinitly
                        showLoading(false);
                    }
                });

    }

    @Override
    public void onResume() {
        super.onResume();

        // Coming from a search request
        if (isSearchRequest()) {
            resetData();

            Intent intent = getActivity().getIntent();

            mCurrentSearchText = intent.getStringExtra(SearchManager.QUERY);
        }

        // Updating product list
        updateProductList();
    }

    /**
     * Return true if we come from a search request
     *
     * @return
     */
    protected boolean isSearchRequest() {
        Intent intent = getActivity().getIntent();

        return (intent != null && StringUtils.equals(Intent.ACTION_SEARCH, intent.getAction())
                && intent.hasExtra(SearchManager.QUERY)) || StringUtils.isNotBlank(mCurrentSearchText);
    }

    protected void onResponseSearch(String requestId, List<ProductSimple> products,
            SpellingSuggestion spellingSuggestion, Pagination pagination) {
        mInitialCall = false;

        // TODO - offline -  when offline work with the local search
        // We create a cursor based on the results, to use the same adapter as the one used for the product list from a category
        if (products != null) {

            List<DataBaseDataSimple> dataList = new ArrayList<>();

            for (ProductSimple product : products) {
                dataList.add(new DataBaseDataSimple(product.getCode(), product.getData(),
                        CatalogContract.SyncStatus.UPTODATE));
            }

            // Merging old with new cursor - in case of pagination
            Cursor oldCursor = mProductItemsAdapter.getCursor();
            Cursor newCursor = CatalogDatabaseHelper.createCursor(dataList);
            MergeCursor mergeCursor;

            if (oldCursor != null && oldCursor.getCount() > 0) {
                mergeCursor = new MergeCursor(new Cursor[] { oldCursor, newCursor });
            } else {
                mergeCursor = new MergeCursor(new Cursor[] { newCursor });
            }

            mProductItemsAdapter.swapCursor(mergeCursor);
        }

        updateUI(StringUtils.equals(requestId, mSearchRequestId), spellingSuggestion,
                pagination != null ? pagination.getTotalResults() : 0);

        mOnCategorySelectedActivated = true;
    }

    public void onErrorSearch(Response<ErrorList> response) {
        UIUtils.showError(response, getActivity());
    }

    /**
     * Update the product list
     */
    protected void updateProductList() {
        // We try first to use the search query
        if (StringUtils.isNotBlank(mCurrentSearchText)) {
            updateProductListFromSearch();
        }
        // Then the category
        else {
            updateProductListFromCategory();
        }
    }

    /**
     * Call to update the product list from a category
     */
    protected void updateProductListFromCategory() {
        if (mCurrentCategory != null) {
            QueryProducts queryProducts = new QueryProducts();
            queryProducts.setIdCategory(mCurrentCategory.getId());
            queryProducts.setCurrentPage(mCurrentPage);
            queryProducts.setPageSize(CommerceApplication.getConfiguration().getDefaultPageSize());

            mProductListLoader.setLimitFrom(0);
            mProductListLoader
                    .setLimitTo((mCurrentPage + 1) * CommerceApplication.getConfiguration().getDefaultPageSize());
            mProductListLoader.updateQuery(queryProducts);
            getLoaderManager().restartLoader(0, null, mProductListLoader);
        }
    }

    /**
     * Call to update the product list from a search query
     */
    protected void updateProductListFromSearch() {

        if (StringUtils.isNotBlank(mCurrentSearchText)) {
            mOnCategorySelectedActivated = false;
            mActivity.onSearchRequest();

            QueryProducts queryProducts = new QueryProducts();
            queryProducts.setQuery(mCurrentSearchText);
            queryProducts.setCurrentPage(mCurrentPage);
            queryProducts.setPageSize(CommerceApplication.getConfiguration().getDefaultPageSize());

            updateProductListFromSearchAbstract(mSearchRequestId, queryProducts, false, new OnRequestListener() {

                @Override
                public void beforeRequest() {
                    showLoading(true);
                }

                @Override
                public void afterRequestBeforeResponse() {

                }

                @Override
                public void afterRequest(boolean isDataSynced) {
                    showLoading(false);
                }
            });

        }
    }

    /**
     * Called when a category is selected
     *
     * @param category
     */
    public void onCategorySelected(CategoryHierarchy category) {
        // Update the breadcrum
        updateBreadcrum(category);

        if (mOnCategorySelectedActivated) {
            // Reset the data
            resetData();

            // Clearing the infinite scroll parameter
            mInfiniteScrollListener.reset();

            // Updating category
            mCurrentCategory = category;

            // Resetting search
            mSearchHeader.setVisibility(View.GONE);

            // Updating the product list
            updateProductList();
        }
    }

    /**
     * Update the breadcrum
     */
    public void updateBreadcrum(CategoryHierarchy category) {
        // Updating the breadcrum
        if (category != null) {
            mCategoryBreadcrumb.setText(getString(R.string.catalog_content_breadcrumb));

            // Category
            if (category.getParent() != null) {
                mCategoryBreadcrumb.setText(mCategoryBreadcrumb.getText() + category.getParent().getName() + " / ");
            }

            mCategoryBreadcrumb.setText(mCategoryBreadcrumb.getText() + category.getName());
        }
    }

    /**
     * Update the UI
     *
     * @param requestFromSearchQuery
     */
    public void updateUI(boolean requestFromSearchQuery, SpellingSuggestion spellingSuggestion, long totalResults) {

        // Updating the breadcrum
        updateBreadcrum(mCurrentCategory);

        // No results (On the initial call we don't display this page as the content provider return the results twice (local then remote), the first results might be empty)
        if (totalResults == 0 && mCurrentPage == 0 && !mInitialCall) {

            // Display the no product view and hide the product list
            showProductItemsView(false);

            // Hide the product items view
            mNoProductFoundView.setVisibility(View.VISIBLE);

            if (requestFromSearchQuery) {
                mSearchHeader.setVisibility(View.GONE);
                mNoProductFoundViewImage.setVisibility(View.VISIBLE);
                mNoProductFoundTextView
                        .setText(getString(R.string.products_not_found_search_request, mCurrentSearchText));

                // Spelling suggestions
                if (spellingSuggestion != null && StringUtils.isNotBlank(spellingSuggestion.getSuggestion())) {
                    mNoProductFoundDidYouMeanView.setVisibility(View.VISIBLE);
                    mNoProductFoundDidYouMeanTextView.setText(spellingSuggestion.getSuggestion());
                } else {
                    mNoProductFoundDidYouMeanView.setVisibility(View.GONE);
                }

            } else {
                mNoProductFoundViewImage.setVisibility(View.GONE);
                mNoProductFoundTextView.setText(getString(R.string.products_not_found));
                mNoProductFoundDidYouMeanView.setVisibility(View.GONE);
            }

        }
        // Displaying the results
        else {
            // Hide the no product view and display the product list
            mNoProductFoundView.setVisibility(View.GONE);

            // Show the correct product items view
            showProductItemsView(true);

            // Display the search header with did you mean and number of results
            if (requestFromSearchQuery) {
                mSearchHeader.setVisibility(View.VISIBLE);
                mSearchHeaderSearched.setText(mCurrentSearchText);
                mSearchHeaderNbResults.setText(getString(R.string.products_search_header_nb_results, totalResults));

                // Spelling suggestions
                if (spellingSuggestion != null && StringUtils.isNotBlank(spellingSuggestion.getSuggestion())) {
                    mSearchHeaderDidYouMeanView.setVisibility(View.VISIBLE);
                    mSearchHeaderDidYouMean.setText(spellingSuggestion.getSuggestion());
                } else {
                    mSearchHeaderDidYouMeanView.setVisibility(View.GONE);
                }
            }
        }

    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putParcelable(SAVED_INSTANCE_CATEGORY, mCurrentCategory);
        outState.putString(SAVED_INSTANCE_SEARCH_TEXT, mCurrentSearchText);
        super.onSaveInstanceState(outState);
    }

    /**
     * Show the loading spinner
     *
     * @param show
     */
    protected void showLoading(boolean show) {
        // Adding the loading view for the list view
        if (mProductListView.getVisibility() == View.VISIBLE) {
            if (show) {
                if (mProductListView.getFooterViewsCount() == 0) {
                    mProductListView.addFooterView(mFooterLoadingListView, null, false);
                }
            } else {
                mProductListView.removeFooterView(mFooterLoadingListView);
            }
        }
        // Adding the loading view for the list view
        else if (mProductGridView.getVisibility() == View.VISIBLE) {
            UIUtils.showLoadingActionBar(getActivity(), show);
        }

    }

    /**
     * Select the view for products
     *
     * @param position
     */
    protected void selectView(int position) {

        // Show the correct view
        // Product list not empty OR product list empty and the view no product found is not shown (first call of the page)
        showProductItemsView(mProductItemsAdapter != null
                && (!mProductItemsAdapter.isEmpty() || (!mNoProductFoundView.isShown())));

        switch (position) {
        case 0:
        default:
            mProductListView.setContentDescription(getString(R.string.catalog_content_header_list_view));
            mProductItemsAdapter = new ProductListAdapter(getActivity(), mProductItemsAdapter.getCursor(), 0,
                    CommerceApplication.getContentServiceHelper());
            break;
        case 1:
            mProductGridView.setContentDescription(getString(R.string.catalog_content_header_grid_view));
            mProductItemsAdapter = new ProductGridAdapter(getActivity(), mProductItemsAdapter.getCursor(), 0,
                    CommerceApplication.getContentServiceHelper());
            break;
        }

        // Listview
        if (position == 0) {
            // When changing the adapter we need to re-add the footer view
            if (mProductListView.getFooterViewsCount() == 0) {
                mProductListView.addFooterView(mFooterLoadingListView, null, false);
            }

            mProductListView.setAdapter(mProductItemsAdapter);
        } else {
            mProductGridView.setAdapter(mProductItemsAdapter);
        }

        if (getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
            mProductGridView.setNumColumns(getResources().getInteger(R.integer.grid_landscape_nb_items));
        } else {
            mProductGridView.setNumColumns(getResources().getInteger(R.integer.grid_portrait_nb_items));
        }

        // Updating the cursor adapter in the loader
        mProductListLoader.setCursorAdapter(mProductItemsAdapter);
    }

    /**
     * Reset the data
     */
    protected void resetData() {
        mProductItemsAdapter.swapCursor(null);
        mProductItemsAdapter.notifyDataSetChanged();
        mCurrentPage = 0;
        mCurrentCategory = null;
        mCurrentSearchText = null;

        // When offline, there is just one call to the provider (No sync request are made on the provider side)
        // TODO - offline - base this value with the isDataSynced of the callabck response
        mInitialCall = CommerceApplication.isOnline();
    }

    /**
     * Show/Hide the correct product items view
     *
     * @param show
     */
    protected void showProductItemsView(boolean show) {
        switch (mItemViewTypeSpinner.getSelectedItemPosition()) {
        // List/Line view
        case 0:
        default:
            mProductListView.setVisibility(show ? View.VISIBLE : View.GONE);
            mProductGridView.setVisibility(View.GONE);
            break;
        // Grid view
        case 1:
            mProductListView.setVisibility(View.GONE);
            mProductGridView.setVisibility(show ? View.VISIBLE : View.GONE);
            break;
        }
    }

    @Override
    public void onStop() {
        super.onStop();

        CommerceApplication.getContentServiceHelper().cancel(mSearchRequestId);
    }

    protected abstract void updateProductListFromSearchAbstract(String requestId, QueryProducts queryProducts,
            boolean shouldUseCache, OnRequestListener onRequestListener);

    /**
     * Interface for activity communication
     */
    public interface OnSearchRequestListener {
        /**
         * Method for callback
         */
        void onSearchRequest();
    }

    static class ProductSimple {
        private String code;
        private String data;

        ProductSimple(String code, String data) {
            this.code = code;
            this.data = data;
        }

        public String getData() {
            return data;
        }

        public void setData(String data) {
            this.data = data;
        }

        public String getCode() {
            return code;
        }

        public void setCode(String code) {
            this.code = code;
        }
    }

    /**
     * Listener for handling changes on view type
     */
    public class ItemViewTypeSpinnerListener implements OnItemSelectedListener {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            SessionHelper.setCatalogContentViewType(position);
            selectView(SessionHelper.getCatalogContentViewType());
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        }
    }
}