package bf.io.openshop.ux.fragments; import android.os.Bundle; import android.os.SystemClock; import android.support.annotation.NonNull; import android.support.v4.app.Fragment; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import java.util.List; import bf.io.openshop.CONST; import bf.io.openshop.MyApplication; import bf.io.openshop.R; import bf.io.openshop.SettingsMy; import bf.io.openshop.api.EndPoints; import bf.io.openshop.api.GsonRequest; import bf.io.openshop.entities.drawerMenu.DrawerItemCategory; import bf.io.openshop.entities.drawerMenu.DrawerItemPage; import bf.io.openshop.entities.drawerMenu.DrawerResponse; import bf.io.openshop.interfaces.DrawerRecyclerInterface; import bf.io.openshop.interfaces.DrawerSubmenuRecyclerInterface; import bf.io.openshop.utils.MsgUtils; import bf.io.openshop.ux.adapters.DrawerRecyclerAdapter; import bf.io.openshop.ux.adapters.DrawerSubmenuRecyclerAdapter; import timber.log.Timber; /** * Fragment handles the drawer menu. */ public class DrawerFragment extends Fragment { private static final int BANNERS_ID = -123; public static final String NULL_DRAWER_LISTENER_WTF = "Null drawer listener. WTF."; private ProgressBar drawerProgress; /** * Button to reload drawer menu content (used when content failed to load). */ private Button drawerRetryBtn; /** * Indicates that menu is currently loading. */ private boolean drawerLoading = false; /** * Listener indicating events that occurred on the menu. */ private FragmentDrawerListener drawerListener; private ActionBarDrawerToggle mDrawerToggle; // Drawer top menu fields. private DrawerLayout mDrawerLayout; private RecyclerView drawerRecycler; private DrawerRecyclerAdapter drawerRecyclerAdapter; // Drawer sub menu fields private LinearLayout drawerSubmenuLayout; private TextView drawerSubmenuTitle; private DrawerSubmenuRecyclerAdapter drawerSubmenuRecyclerAdapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Timber.d("%s - onCreateView", this.getClass().getSimpleName()); // Inflating view layout View layout = inflater.inflate(R.layout.fragment_drawer, container, false); drawerSubmenuLayout = (LinearLayout) layout.findViewById(R.id.drawer_submenu_layout); drawerSubmenuTitle = (TextView) layout.findViewById(R.id.drawer_submenu_title); drawerProgress = (ProgressBar) layout.findViewById(R.id.drawer_progress); drawerRetryBtn = (Button) layout.findViewById(R.id.drawer_retry_btn); drawerRetryBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!drawerLoading) getDrawerItems(); } }); prepareDrawerRecycler(layout); Button backBtn = (Button) layout.findViewById(R.id.drawer_submenu_back_btn); backBtn.setOnClickListener(new View.OnClickListener() { private long mLastClickTime = 0; @Override public void onClick(View v) { if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) return; mLastClickTime = SystemClock.elapsedRealtime(); animateSubListHide(); } }); getDrawerItems(); return layout; } /** * Prepare drawer menu content views, adapters and listeners. * * @param view fragment base view. */ private void prepareDrawerRecycler(View view) { drawerRecycler = (RecyclerView) view.findViewById(R.id.drawer_recycler); drawerRecyclerAdapter = new DrawerRecyclerAdapter(getContext(), new DrawerRecyclerInterface() { @Override public void onCategorySelected(View v, DrawerItemCategory drawerItemCategory) { if (drawerItemCategory.getChildren() == null || drawerItemCategory.getChildren().isEmpty()) { if (drawerListener != null) { if (drawerItemCategory.getId() == BANNERS_ID) drawerListener.onDrawerBannersSelected(); else drawerListener.onDrawerItemCategorySelected(drawerItemCategory); closeDrawerMenu(); } else { Timber.e(new RuntimeException(), NULL_DRAWER_LISTENER_WTF); } } else animateSubListShow(drawerItemCategory); } @Override public void onPageSelected(View v, DrawerItemPage drawerItemPage) { if (drawerListener != null) { drawerListener.onDrawerItemPageSelected(drawerItemPage); closeDrawerMenu(); } else { Timber.e(new RuntimeException(), NULL_DRAWER_LISTENER_WTF); } } @Override public void onHeaderSelected() { if (drawerListener != null) { drawerListener.onAccountSelected(); closeDrawerMenu(); } else { Timber.e(new RuntimeException(), NULL_DRAWER_LISTENER_WTF); } } }); drawerRecycler.setLayoutManager(new LinearLayoutManager(getContext())); drawerRecycler.setHasFixedSize(true); drawerRecycler.setAdapter(drawerRecyclerAdapter); RecyclerView drawerSubmenuRecycler = (RecyclerView) view.findViewById(R.id.drawer_submenu_recycler); drawerSubmenuRecyclerAdapter = new DrawerSubmenuRecyclerAdapter(new DrawerSubmenuRecyclerInterface() { @Override public void onSubCategorySelected(View v, DrawerItemCategory drawerItemCategory) { if (drawerListener != null) { drawerListener.onDrawerItemCategorySelected(drawerItemCategory); closeDrawerMenu(); } } }); drawerSubmenuRecycler.setLayoutManager(new LinearLayoutManager(getContext())); drawerSubmenuRecycler.setItemAnimator(new DefaultItemAnimator()); drawerSubmenuRecycler.setHasFixedSize(true); drawerSubmenuRecycler.setAdapter(drawerSubmenuRecyclerAdapter); } /** * Base method for layout preparation. Also set a listener that will respond to events that occurred on the menu. * * @param drawerLayout drawer layout, which will be managed. * @param toolbar toolbar bundled with a side menu. * @param eventsListener corresponding listener class. */ public void setUp(DrawerLayout drawerLayout, final Toolbar toolbar, FragmentDrawerListener eventsListener) { mDrawerLayout = drawerLayout; this.drawerListener = eventsListener; mDrawerToggle = new ActionBarDrawerToggle(getActivity(), drawerLayout, toolbar, R.string.content_description_open_navigation_drawer, R.string.content_description_close_navigation_drawer) { @Override public void onDrawerOpened(View drawerView) { super.onDrawerOpened(drawerView); getActivity().invalidateOptionsMenu(); } @Override public void onDrawerClosed(View drawerView) { super.onDrawerClosed(drawerView); getActivity().invalidateOptionsMenu(); } @Override public void onDrawerSlide(View drawerView, float slideOffset) { super.onDrawerSlide(drawerView, slideOffset); // toolbar.setAlpha(1 - slideOffset / 2); } }; toolbar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { toggleDrawerMenu(); } }); mDrawerLayout.addDrawerListener(mDrawerToggle); mDrawerLayout.post(new Runnable() { @Override public void run() { mDrawerToggle.syncState(); } }); } /** * When the drawer menu is open, close it. Otherwise open it. */ public void toggleDrawerMenu() { if (mDrawerLayout != null) { if (mDrawerLayout.isDrawerVisible(GravityCompat.START)) { mDrawerLayout.closeDrawer(GravityCompat.START); } else { mDrawerLayout.openDrawer(GravityCompat.START); } } } /** * When the drawer menu is open, close it. */ public void closeDrawerMenu() { if (mDrawerLayout != null) { mDrawerLayout.closeDrawer(GravityCompat.START); } } /** * Check if drawer is open. If so close it. * * @return false if drawer was already closed */ public boolean onBackHide() { if (mDrawerLayout != null && mDrawerLayout.isDrawerVisible(GravityCompat.START)) { if (drawerSubmenuLayout.getVisibility() == View.VISIBLE) animateSubListHide(); else mDrawerLayout.closeDrawer(GravityCompat.START); return true; } return false; } /** * Method invalidates a drawer menu header. It is used primarily on a login state change. */ public void invalidateHeader() { if (drawerRecyclerAdapter != null) { Timber.d("Invalidate drawer menu header."); drawerRecyclerAdapter.notifyItemChanged(0); } } private void getDrawerItems() { drawerLoading = true; drawerProgress.setVisibility(View.VISIBLE); drawerRetryBtn.setVisibility(View.GONE); String url = String.format(EndPoints.NAVIGATION_DRAWER, SettingsMy.getActualNonNullShop(getActivity()).getId()); GsonRequest<DrawerResponse> getDrawerMenu = new GsonRequest<>(Request.Method.GET, url, null, DrawerResponse.class, new Response.Listener<DrawerResponse>() { @Override public void onResponse(@NonNull DrawerResponse drawerResponse) { drawerRecyclerAdapter.addDrawerItem(new DrawerItemCategory(BANNERS_ID, BANNERS_ID, getString(R.string.Just_arrived))); drawerRecyclerAdapter.addDrawerItemList(drawerResponse.getNavigation()); drawerRecyclerAdapter.addPageItemList(drawerResponse.getPages()); drawerRecyclerAdapter.notifyDataSetChanged(); if (drawerListener != null) drawerListener.prepareSearchSuggestions(drawerResponse.getNavigation()); drawerLoading = false; if (drawerRecycler != null) drawerRecycler.setVisibility(View.VISIBLE); if (drawerProgress != null) drawerProgress.setVisibility(View.GONE); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { MsgUtils.logAndShowErrorMessage(getActivity(), error); drawerLoading = false; if (drawerProgress != null) drawerProgress.setVisibility(View.GONE); if (drawerRetryBtn != null) drawerRetryBtn.setVisibility(View.VISIBLE); } }); getDrawerMenu.setRetryPolicy(MyApplication.getDefaultRetryPolice()); getDrawerMenu.setShouldCache(false); MyApplication.getInstance().addToRequestQueue(getDrawerMenu, CONST.DRAWER_REQUESTS_TAG); } private void animateSubListHide() { Animation slideAwayDisappear = AnimationUtils.loadAnimation(getActivity(), R.anim.slide_away_disappear); final Animation slideAwayAppear = AnimationUtils.loadAnimation(getActivity(), R.anim.slide_away_appear); slideAwayDisappear.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { drawerRecycler.setVisibility(View.VISIBLE); drawerRecycler.startAnimation(slideAwayAppear); } @Override public void onAnimationEnd(Animation animation) { drawerSubmenuLayout.setVisibility(View.GONE); } @Override public void onAnimationRepeat(Animation animation) { } }); drawerSubmenuLayout.startAnimation(slideAwayDisappear); } private void animateSubListShow(DrawerItemCategory drawerItemCategory) { if (drawerItemCategory != null) { drawerSubmenuTitle.setText(drawerItemCategory.getName()); drawerSubmenuRecyclerAdapter.changeDrawerItems(drawerItemCategory.getChildren()); Animation slideInDisappear = AnimationUtils.loadAnimation(getActivity(), R.anim.slide_in_disappear); final Animation slideInAppear = AnimationUtils.loadAnimation(getActivity(), R.anim.slide_in_appear); slideInDisappear.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { drawerSubmenuLayout.setVisibility(View.VISIBLE); drawerSubmenuLayout.startAnimation(slideInAppear); } @Override public void onAnimationEnd(Animation animation) { drawerRecycler.setVisibility(View.GONE); } @Override public void onAnimationRepeat(Animation animation) { } }); drawerRecycler.startAnimation(slideInDisappear); } else { Timber.e("Populate submenu with null category drawer item."); } } @Override public void onPause() { // Cancellation during onPause is needed because of app restarting during changing shop. MyApplication.getInstance().cancelPendingRequests(CONST.DRAWER_REQUESTS_TAG); if (drawerLoading) { if (drawerProgress != null) drawerProgress.setVisibility(View.GONE); if (drawerRetryBtn != null) drawerRetryBtn.setVisibility(View.VISIBLE); drawerLoading = false; } super.onPause(); } @Override public void onDestroy() { mDrawerLayout.removeDrawerListener(mDrawerToggle); super.onDestroy(); } /** * Interface defining events initiated by {@link DrawerFragment}. */ public interface FragmentDrawerListener { /** * Launch {@link BannersFragment}. If fragment is already launched nothing happen. */ void onDrawerBannersSelected(); /** * Launch {@link CategoryFragment}. * * @param drawerItemCategory object specifying selected item in the drawer. */ void onDrawerItemCategorySelected(DrawerItemCategory drawerItemCategory); /** * Launch {@link PageFragment}, with downloadable content. * * @param drawerItemPage id of page for download and display. (Define in OpenShop server administration) */ void onDrawerItemPageSelected(DrawerItemPage drawerItemPage); /** * Launch {@link AccountFragment}. */ void onAccountSelected(); /** * Prepare all search strings for search whisperer. * * @param navigation items for suggestions generating. */ void prepareSearchSuggestions(List<DrawerItemCategory> navigation); } }