2019-09-18 22:29:09 +02:00

1900 lines
67 KiB
Java

package com.mikepenz.materialdrawer;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.DimenRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.MenuRes;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.core.view.GravityCompat;
import androidx.core.view.ViewCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.view.SupportMenuInflater;
import androidx.appcompat.view.menu.MenuBuilder;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.appcompat.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.mikepenz.fastadapter.FastAdapter;
import com.mikepenz.fastadapter.IAdapter;
import com.mikepenz.fastadapter.IAdapterExtension;
import com.mikepenz.fastadapter.IExpandable;
import com.mikepenz.fastadapter.IItemAdapter;
import com.mikepenz.fastadapter.adapters.ItemAdapter;
import com.mikepenz.fastadapter.adapters.ModelAdapter;
import com.mikepenz.fastadapter.expandable.ExpandableExtension;
import com.mikepenz.fastadapter.listeners.OnClickListener;
import com.mikepenz.fastadapter.listeners.OnLongClickListener;
import com.mikepenz.fastadapter.utils.DefaultIdDistributor;
import com.mikepenz.fastadapter.utils.DefaultIdDistributorImpl;
import com.mikepenz.iconics.utils.Utils;
import com.mikepenz.materialdrawer.holder.DimenHolder;
import com.mikepenz.materialdrawer.model.AbstractDrawerItem;
import com.mikepenz.materialdrawer.model.DividerDrawerItem;
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.Selectable;
import com.mikepenz.materialdrawer.util.DrawerUIUtils;
import com.mikepenz.materialize.Materialize;
import com.mikepenz.materialize.MaterializeBuilder;
import com.mikepenz.materialize.util.UIUtils;
import com.mikepenz.materialize.view.ScrimInsetsRelativeLayout;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Created by mikepenz on 23.05.15.
*/
public class DrawerBuilder {
// some internal vars
// variable to check if a builder is only used once
protected boolean mUsed = false;
protected int mCurrentStickyFooterSelection = -1;
protected boolean mAppended = false;
// the activity to use
protected Activity mActivity;
protected RecyclerView.LayoutManager mLayoutManager;
protected ViewGroup mRootView;
protected Materialize mMaterialize;
public final DefaultIdDistributor idDistributor = new DefaultIdDistributorImpl();
/**
* default constructor
*/
public DrawerBuilder() {
getAdapter();
}
/**
* Construct a Drawer by passing the activity to use for the generation
*
* @param activity current activity which will contain the drawer
*/
public DrawerBuilder(@NonNull Activity activity) {
this.mRootView = (ViewGroup) activity.findViewById(android.R.id.content);
this.mActivity = activity;
this.mLayoutManager = new LinearLayoutManager(mActivity);
getAdapter();
}
/**
* Sets the activity which will be generated for the generation
* The activity is required and will be used to inflate the content in.
* After generation it is set to null to prevent a memory leak.
*
* @param activity current activity which will contain the drawer
*/
public DrawerBuilder withActivity(@NonNull Activity activity) {
this.mRootView = (ViewGroup) activity.findViewById(android.R.id.content);
this.mActivity = activity;
this.mLayoutManager = new LinearLayoutManager(mActivity);
return this;
}
/**
* Sets the rootView which will host the DrawerLayout
* The content of this view will be extracted and added as the new content inside the drawerLayout
*
* @param rootView a view which will get switched out by the DrawerLayout and added as its child
*/
public DrawerBuilder withRootView(@NonNull ViewGroup rootView) {
this.mRootView = rootView;
//disable the translucent statusBar we don't need it
withTranslucentStatusBar(false);
return this;
}
/**
* Sets the rootView which will host the DrawerLayout
* The content of this view will be extracted and added as the new content inside the drawerLayout
*
* @param rootViewRes the id of a view which will get switched out by the DrawerLayout and added as its child
*/
public DrawerBuilder withRootView(@IdRes int rootViewRes) {
if (mActivity == null) {
throw new RuntimeException("please pass an activity first to use this call");
}
return withRootView((ViewGroup) mActivity.findViewById(rootViewRes));
}
// set non translucent statusBar mode
protected boolean mTranslucentStatusBar = true;
/**
* Sets that the view which hosts the DrawerLayout should have a translucent statusBar
* This is true by default, so it's possible to display the drawer under the statusBar
*
* @param translucentStatusBar sets whether the statusBar is transparent (and the drawer is displayed under it) or not
*/
public DrawerBuilder withTranslucentStatusBar(boolean translucentStatusBar) {
this.mTranslucentStatusBar = translucentStatusBar;
return this;
}
// set if we want to display the specific Drawer below the statusBar
protected Boolean mDisplayBelowStatusBar;
/**
* Sets that the slider of this Drawer should be displayed below the statusBar even with a translucentStatusBar
*
* @param displayBelowStatusBar sets wheter the slider of the drawer is displayed below the statusBar or not
*/
public DrawerBuilder withDisplayBelowStatusBar(boolean displayBelowStatusBar) {
this.mDisplayBelowStatusBar = displayBelowStatusBar;
return this;
}
//defines if we want a inner shadow (used in with the MiniDrawer)
private boolean mInnerShadow = false;
/**
* sets if the drawer should show an inner shadow or not
*
* @param innerShadow sets wheter the drawer should display an inner shadow or not
* @return
*/
public DrawerBuilder withInnerShadow(boolean innerShadow) {
this.mInnerShadow = innerShadow;
return this;
}
// the toolbar of the activity
protected Toolbar mToolbar;
/**
* Sets the toolbar which should be used in combination with the drawer
* This will handle the ActionBarDrawerToggle for you.
* Do not set this if you are in a sub activity and want to handle the back arrow on your own
*
* @param toolbar the toolbar which is used in combination with the drawer
*/
public DrawerBuilder withToolbar(@NonNull Toolbar toolbar) {
this.mToolbar = toolbar;
return this;
}
// set non translucent NavigationBar mode
protected boolean mTranslucentNavigationBar = false;
/**
* Set to true if you use a translucent NavigationBar
*
* @param translucentNavigationBar
* @return
*/
public DrawerBuilder withTranslucentNavigationBar(boolean translucentNavigationBar) {
this.mTranslucentNavigationBar = translucentNavigationBar;
//if we disable the translucentNavigationBar it should be disabled at all
if (!translucentNavigationBar) {
this.mTranslucentNavigationBarProgrammatically = false;
}
return this;
}
// set to disable the translucent statusBar Programmatically
protected boolean mTranslucentNavigationBarProgrammatically = false;
/**
* set this to true if you want a translucent navigation bar.
*
* @param translucentNavigationBarProgrammatically
* @return
*/
public DrawerBuilder withTranslucentNavigationBarProgrammatically(boolean translucentNavigationBarProgrammatically) {
this.mTranslucentNavigationBarProgrammatically = translucentNavigationBarProgrammatically;
//if we enable the programmatically translucent navigationBar we want also the normal navigationBar behavior
if (translucentNavigationBarProgrammatically) {
this.mTranslucentNavigationBar = true;
}
return this;
}
// set non translucent NavigationBar mode
protected boolean mFullscreen = false;
/**
* Set to true if the used theme has a translucent statusBar
* and navigationBar and you want to manage the padding on your own.
*
* @param fullscreen
* @return
*/
public DrawerBuilder withFullscreen(boolean fullscreen) {
this.mFullscreen = fullscreen;
if (fullscreen) {
withTranslucentStatusBar(true);
withTranslucentNavigationBar(false);
}
return this;
}
// set to no systemUI visible mode
protected boolean mSystemUIHidden = false;
/**
* Set to true if you use your app in complete fullscreen mode
* with hidden statusBar and navigationBar
*
* @param systemUIHidden
* @return
*/
public DrawerBuilder withSystemUIHidden(boolean systemUIHidden) {
this.mSystemUIHidden = systemUIHidden;
if (systemUIHidden) {
withFullscreen(systemUIHidden);
}
return this;
}
// a custom view to be used instead of everything else
protected View mCustomView;
/**
* Pass a custom view if you need a completely custom drawer
* content
*
* @param customView
* @return
*/
public DrawerBuilder withCustomView(@NonNull View customView) {
this.mCustomView = customView;
return this;
}
// the drawerLayout to use
protected DrawerLayout mDrawerLayout;
protected ScrimInsetsRelativeLayout mSliderLayout;
/**
* Pass a custom DrawerLayout which will be used.
* NOTE: This requires the same structure as the drawer.xml
*
* @param drawerLayout
* @return
*/
public DrawerBuilder withDrawerLayout(@NonNull DrawerLayout drawerLayout) {
this.mDrawerLayout = drawerLayout;
return this;
}
/**
* Pass a custom DrawerLayout Resource which will be used.
* NOTE: This requires the same structure as the drawer.xml
*
* @param resLayout
* @return
*/
public DrawerBuilder withDrawerLayout(@LayoutRes int resLayout) {
if (mActivity == null) {
throw new RuntimeException("please pass an activity first to use this call");
}
if (resLayout != -1) {
this.mDrawerLayout = (DrawerLayout) mActivity.getLayoutInflater().inflate(resLayout, mRootView, false);
} else {
if (Build.VERSION.SDK_INT < 21) {
this.mDrawerLayout = (DrawerLayout) mActivity.getLayoutInflater().inflate(R.layout.material_drawer_fits_not, mRootView, false);
} else {
this.mDrawerLayout = (DrawerLayout) mActivity.getLayoutInflater().inflate(R.layout.material_drawer, mRootView, false);
}
}
return this;
}
//the background color for the slider
protected int mSliderBackgroundColor = 0;
protected int mSliderBackgroundColorRes = -1;
protected Drawable mSliderBackgroundDrawable = null;
protected int mSliderBackgroundDrawableRes = -1;
/**
* Set the background color for the Slider.
* This is the view containing the list.
*
* @param sliderBackgroundColor
* @return
*/
public DrawerBuilder withSliderBackgroundColor(@ColorInt int sliderBackgroundColor) {
this.mSliderBackgroundColor = sliderBackgroundColor;
return this;
}
/**
* Set the background color for the Slider from a Resource.
* This is the view containing the list.
*
* @param sliderBackgroundColorRes
* @return
*/
public DrawerBuilder withSliderBackgroundColorRes(@ColorRes int sliderBackgroundColorRes) {
this.mSliderBackgroundColorRes = sliderBackgroundColorRes;
return this;
}
/**
* Set the background drawable for the Slider.
* This is the view containing the list.
*
* @param sliderBackgroundDrawable
* @return
*/
public DrawerBuilder withSliderBackgroundDrawable(@NonNull Drawable sliderBackgroundDrawable) {
this.mSliderBackgroundDrawable = sliderBackgroundDrawable;
return this;
}
/**
* Set the background drawable for the Slider from a Resource.
* This is the view containing the list.
*
* @param sliderBackgroundDrawableRes
* @return
*/
public DrawerBuilder withSliderBackgroundDrawableRes(@DrawableRes int sliderBackgroundDrawableRes) {
this.mSliderBackgroundDrawableRes = sliderBackgroundDrawableRes;
return this;
}
//the width of the drawer
protected int mDrawerWidth = -1;
/**
* Set the DrawerBuilder width with a pixel value
*
* @param drawerWidthPx
* @return
*/
public DrawerBuilder withDrawerWidthPx(int drawerWidthPx) {
this.mDrawerWidth = drawerWidthPx;
return this;
}
/**
* Set the DrawerBuilder width with a dp value
*
* @param drawerWidthDp
* @return
*/
public DrawerBuilder withDrawerWidthDp(int drawerWidthDp) {
if (mActivity == null) {
throw new RuntimeException("please pass an activity first to use this call");
}
this.mDrawerWidth = Utils.convertDpToPx(mActivity, drawerWidthDp);
return this;
}
/**
* Set the DrawerBuilder width with a dimension resource
*
* @param drawerWidthRes
* @return
*/
public DrawerBuilder withDrawerWidthRes(@DimenRes int drawerWidthRes) {
if (mActivity == null) {
throw new RuntimeException("please pass an activity first to use this call");
}
this.mDrawerWidth = mActivity.getResources().getDimensionPixelSize(drawerWidthRes);
return this;
}
//the gravity of the drawer
protected Integer mDrawerGravity = GravityCompat.START;
/**
* Set the gravity for the drawer. START, LEFT | RIGHT, END
*
* @param gravity
* @return
*/
public DrawerBuilder withDrawerGravity(int gravity) {
this.mDrawerGravity = gravity;
return this;
}
//the account selection header to use
protected AccountHeader mAccountHeader;
protected boolean mAccountHeaderSticky = false;
/**
* Add a AccountSwitcherHeader which will be used in this drawer instance.
* NOTE: This will overwrite any set headerView.
*
* @param accountHeader
* @return
*/
public DrawerBuilder withAccountHeader(@NonNull AccountHeader accountHeader) {
return withAccountHeader(accountHeader, false);
}
/**
* Add a AccountSwitcherHeader which will be used in this drawer instance. Pass true if it should be sticky
* NOTE: This will overwrite any set headerView or stickyHeaderView (depends on the boolean).
*
* @param accountHeader
* @param accountHeaderSticky
* @return
*/
public DrawerBuilder withAccountHeader(@NonNull AccountHeader accountHeader, boolean accountHeaderSticky) {
this.mAccountHeader = accountHeader;
this.mAccountHeaderSticky = accountHeaderSticky;
return this;
}
// enable/disable the actionBarDrawerToggle animation
protected boolean mAnimateActionBarDrawerToggle = false;
/**
* Set this to true if you want the ActionBarDrawerToggle to be animated.
* NOTE: This will only work if the built in ActionBarDrawerToggle is used.
* Enable it by setting withActionBarDrawerToggle to true
*
* @param actionBarDrawerToggleAnimated
* @return
*/
public DrawerBuilder withActionBarDrawerToggleAnimated(boolean actionBarDrawerToggleAnimated) {
this.mAnimateActionBarDrawerToggle = actionBarDrawerToggleAnimated;
return this;
}
// enable the drawer toggle / if withActionBarDrawerToggle we will autoGenerate it
protected boolean mActionBarDrawerToggleEnabled = true;
/**
* Set this to false if you don't need the included ActionBarDrawerToggle
*
* @param actionBarDrawerToggleEnabled
* @return
*/
public DrawerBuilder withActionBarDrawerToggle(boolean actionBarDrawerToggleEnabled) {
this.mActionBarDrawerToggleEnabled = actionBarDrawerToggleEnabled;
return this;
}
// drawer toggle
protected ActionBarDrawerToggle mActionBarDrawerToggle;
/**
* Add a custom ActionBarDrawerToggle which will be used in combination with this drawer.
*
* @param actionBarDrawerToggle
* @return
*/
public DrawerBuilder withActionBarDrawerToggle(@NonNull ActionBarDrawerToggle actionBarDrawerToggle) {
this.mActionBarDrawerToggleEnabled = true;
this.mActionBarDrawerToggle = actionBarDrawerToggle;
return this;
}
// defines if the drawer should scroll to top after click
protected boolean mScrollToTopAfterClick = false;
/**
* defines if the drawer should scroll to top after click
*
* @param scrollToTopAfterClick
* @return
*/
public DrawerBuilder withScrollToTopAfterClick(boolean scrollToTopAfterClick) {
this.mScrollToTopAfterClick = scrollToTopAfterClick;
return this;
}
// header view
protected View mHeaderView;
protected boolean mHeaderDivider = true;
protected boolean mHeaderPadding = true;
protected DimenHolder mHeiderHeight = null;
/**
* Add a header to the DrawerBuilder ListView. This can be any view
*
* @param headerView
* @return
*/
public DrawerBuilder withHeader(@NonNull View headerView) {
this.mHeaderView = headerView;
return this;
}
/**
* Add a header to the DrawerBuilder ListView defined by a resource.
*
* @param headerViewRes
* @return
*/
public DrawerBuilder withHeader(@LayoutRes int headerViewRes) {
if (mActivity == null) {
throw new RuntimeException("please pass an activity first to use this call");
}
if (headerViewRes != -1) {
//i know there should be a root, bit i got none here
this.mHeaderView = mActivity.getLayoutInflater().inflate(headerViewRes, null, false);
}
return this;
}
/**
* Set this to false if you don't need the divider below the header
*
* @param headerDivider
* @return
*/
public DrawerBuilder withHeaderDivider(boolean headerDivider) {
this.mHeaderDivider = headerDivider;
return this;
}
/**
* Set this to false if you don't need the padding below the header
*
* @param headerPadding
* @return
*/
public DrawerBuilder withHeaderPadding(boolean headerPadding) {
this.mHeaderPadding = headerPadding;
return this;
}
/**
* Sets the header height for the header provided via `withHeader()`
*
* @param headerHeight the DimenHolder with the height we want to set for the header
* @return
*/
public DrawerBuilder withHeaderHeight(DimenHolder headerHeight) {
this.mHeiderHeight = headerHeight;
return this;
}
// sticky view
protected View mStickyHeaderView;
// shadow shown on the top of the sticky header
protected boolean mStickyHeaderShadow = true;
/**
* Add a sticky header below the DrawerBuilder ListView. This can be any view
*
* @param stickyHeader
* @return
*/
public DrawerBuilder withStickyHeader(@NonNull View stickyHeader) {
this.mStickyHeaderView = stickyHeader;
return this;
}
/**
* Add a sticky header below the DrawerBuilder ListView defined by a resource.
*
* @param stickyHeaderRes
* @return
*/
public DrawerBuilder withStickyHeader(@LayoutRes int stickyHeaderRes) {
if (mActivity == null) {
throw new RuntimeException("please pass an activity first to use this call");
}
if (stickyHeaderRes != -1) {
//i know there should be a root, bit i got none here
this.mStickyHeaderView = mActivity.getLayoutInflater().inflate(stickyHeaderRes, null, false);
}
return this;
}
/**
* Set this to false if you don't want the shadow below the sticky header
*
* @param stickyHeaderShadow
* @return
*/
public DrawerBuilder withStickyHeaderShadow(boolean stickyHeaderShadow) {
this.mStickyHeaderShadow = stickyHeaderShadow;
return this;
}
// footer view
protected View mFooterView;
protected boolean mFooterDivider = true;
protected boolean mFooterClickable = false;
/**
* Add a footer to the DrawerBuilder ListView. This can be any view
*
* @param footerView
* @return
*/
public DrawerBuilder withFooter(@NonNull View footerView) {
this.mFooterView = footerView;
return this;
}
/**
* Add a footer to the DrawerBuilder ListView defined by a resource.
*
* @param footerViewRes
* @return
*/
public DrawerBuilder withFooter(@LayoutRes int footerViewRes) {
if (mActivity == null) {
throw new RuntimeException("please pass an activity first to use this call");
}
if (footerViewRes != -1) {
//i know there should be a root, bit i got none here
this.mFooterView = mActivity.getLayoutInflater().inflate(footerViewRes, null, false);
}
return this;
}
/**
* Set this to true if you want the footer to be clickable
*
* @param footerClickable
* @return
*/
public DrawerBuilder withFooterClickable(boolean footerClickable) {
this.mFooterClickable = footerClickable;
return this;
}
/**
* Set this to false if you don't need the divider above the footer
*
* @param footerDivider
* @return
*/
public DrawerBuilder withFooterDivider(boolean footerDivider) {
this.mFooterDivider = footerDivider;
return this;
}
// sticky view
protected ViewGroup mStickyFooterView;
// divider shown on top of the sticky footer
protected boolean mStickyFooterDivider = false;
// sticky view
protected View mStickyFooterShadowView;
// shadow shown on the top of the sticky footer
protected boolean mStickyFooterShadow = true;
/**
* Add a sticky footer below the DrawerBuilder ListView. This can be any view
*
* @param stickyFooter
* @return
*/
public DrawerBuilder withStickyFooter(@NonNull ViewGroup stickyFooter) {
this.mStickyFooterView = stickyFooter;
return this;
}
/**
* Add a sticky footer below the DrawerBuilder ListView defined by a resource.
*
* @param stickyFooterRes
* @return
*/
public DrawerBuilder withStickyFooter(@LayoutRes int stickyFooterRes) {
if (mActivity == null) {
throw new RuntimeException("please pass an activity first to use this call");
}
if (stickyFooterRes != -1) {
//i know there should be a root, bit i got none here
this.mStickyFooterView = (ViewGroup) mActivity.getLayoutInflater().inflate(stickyFooterRes, null, false);
}
return this;
}
/**
* Set this to true if you want the divider above the sticky footer
*
* @param stickyFooterDivider
* @return
*/
public DrawerBuilder withStickyFooterDivider(boolean stickyFooterDivider) {
this.mStickyFooterDivider = stickyFooterDivider;
return this;
}
/**
* Set this to false if you don't want the shadow on top of the sticky footer
*
* @param stickyFooterShadow
* @return
*/
public DrawerBuilder withStickyFooterShadow(boolean stickyFooterShadow) {
this.mStickyFooterShadow = stickyFooterShadow;
return this;
}
// fire onClick after build
protected boolean mFireInitialOnClick = false;
/**
* Set this to true if you love to get an initial onClick event after the build method is called
*
* @param fireOnInitialOnClick
* @return
*/
public DrawerBuilder withFireOnInitialOnClick(boolean fireOnInitialOnClick) {
this.mFireInitialOnClick = fireOnInitialOnClick;
return this;
}
// if multiSelection is possible
protected boolean mMultiSelect = false;
/**
* set this to true if you want to enable multiSelect mode inside the drawer. Note
* you will have to programmatically deselect if you want to remove all selections!
* You can disable this at a later time via .getAdapter().withMultiSelect(false)
* You can also modify all other settings of the FastAdapter via this method
*
* @param multiSelect true if multiSelect is enabled (default: false)
* @return this
*/
public DrawerBuilder withMultiSelect(boolean multiSelect) {
this.mMultiSelect = multiSelect;
return this;
}
// item to select
protected int mSelectedItemPosition = 0;
/**
* Set this to the index of the item, you would love to select upon start
*
* @param selectedItemPosition
* @return
*/
public DrawerBuilder withSelectedItemByPosition(int selectedItemPosition) {
this.mSelectedItemPosition = selectedItemPosition;
return this;
}
// item to select
protected long mSelectedItemIdentifier = 0;
/**
* Set this to the identifier of the item, you would love to select upon start
*
* @param selectedItemIdentifier
* @return
*/
public DrawerBuilder withSelectedItem(long selectedItemIdentifier) {
this.mSelectedItemIdentifier = selectedItemIdentifier;
return this;
}
// an RecyclerView to use within the drawer :D
protected RecyclerView mRecyclerView;
/**
* Define a custom RecyclerView which will be used in the drawer
* NOTE: this is not recommended
*
* @param recyclerView
* @return
*/
public DrawerBuilder withRecyclerView(@NonNull RecyclerView recyclerView) {
this.mRecyclerView = recyclerView;
return this;
}
// if the adapter should enable hasStableIds to improve performance and allow animations
protected boolean mHasStableIds = false;
/**
* define this if you want enable hasStableIds for the adapter which is generated.
* WARNING: only use this if you have set an identifer for all of your items else this could cause
* many weird things
*
* @param hasStableIds
* @return
*/
public DrawerBuilder withHasStableIds(boolean hasStableIds) {
this.mHasStableIds = hasStableIds;
if (mAdapter != null) {
mAdapter.setHasStableIds(hasStableIds);
}
return this;
}
// an adapter to use for the list
protected FastAdapter<IDrawerItem> mAdapter;
protected ModelAdapter<IDrawerItem, IDrawerItem> mHeaderAdapter = new ItemAdapter<>().withIdDistributor(idDistributor);
protected ModelAdapter<IDrawerItem, IDrawerItem> mItemAdapter = new ItemAdapter<>().withIdDistributor(idDistributor);
protected ModelAdapter<IDrawerItem, IDrawerItem> mFooterAdapter = new ItemAdapter<>().withIdDistributor(idDistributor);
protected ExpandableExtension<IDrawerItem> mExpandableExtension = new ExpandableExtension<>();
/**
* Define a custom Adapter which will be used in the drawer
* NOTE: this is not recommender
* WARNING: if you do this after adding items you will loose those!
*
* @param adapter the FastAdapter to use with this drawer
* @return this
*/
public DrawerBuilder withAdapter(@NonNull FastAdapter<IDrawerItem> adapter) {
this.mAdapter = adapter;
//we have to rewrap as a different FastAdapter was provided
adapter.addAdapter(0, mHeaderAdapter);
adapter.addAdapter(1, mItemAdapter);
adapter.addAdapter(2, mFooterAdapter);
adapter.addExtension(mExpandableExtension);
return this;
}
/**
* get the adapter (null safe)
*
* @return the FastAdapter used with this drawer
*/
protected FastAdapter<IDrawerItem> getAdapter() {
if (mAdapter == null) {
mAdapter = FastAdapter.with(Arrays.asList(mHeaderAdapter, mItemAdapter, mFooterAdapter), Arrays.<IAdapterExtension<IDrawerItem>>asList(mExpandableExtension));
mAdapter.withSelectable(true);
mAdapter.withMultiSelect(false);
mAdapter.withAllowDeselection(false);
mAdapter.setHasStableIds(mHasStableIds);
}
return mAdapter;
}
protected IItemAdapter<IDrawerItem, IDrawerItem> getItemAdapter() {
return mItemAdapter;
}
protected IItemAdapter<IDrawerItem, IDrawerItem> getHeaderAdapter() {
return mHeaderAdapter;
}
protected IItemAdapter<IDrawerItem, IDrawerItem> getFooterAdapter() {
return mFooterAdapter;
}
// Defines a Adapter which wraps the main Adapter used in the RecyclerView to allow extended navigation and other stuff
protected RecyclerView.Adapter mAdapterWrapper;
/**
* Defines a Adapter which wraps the main Adapter used in the RecyclerView to allow extended navigation and other stuff
*
* @param adapterWrapper
* @return
*/
public DrawerBuilder withAdapterWrapper(@NonNull RecyclerView.Adapter adapterWrapper) {
if (mAdapter == null) {
throw new RuntimeException("this adapter has to be set in conjunction to a normal adapter which is used inside this wrapper adapter");
}
this.mAdapterWrapper = adapterWrapper;
return this;
}
//defines the itemAnimator to be used in conjunction with the RecyclerView
protected RecyclerView.ItemAnimator mItemAnimator = new DefaultItemAnimator();
/**
* defines the itemAnimator to be used in conjunction with the RecyclerView
*
* @param itemAnimator
* @return
*/
public DrawerBuilder withItemAnimator(RecyclerView.ItemAnimator itemAnimator) {
mItemAnimator = itemAnimator;
return this;
}
/**
* Set the initial List of IDrawerItems for the Drawer
*
* @param drawerItems
* @return
*/
public DrawerBuilder withDrawerItems(@NonNull List<IDrawerItem> drawerItems) {
this.getItemAdapter().set(drawerItems);
return this;
}
/**
* Add a initial DrawerItem or a DrawerItem Array for the Drawer
*
* @param drawerItems
* @return
*/
public DrawerBuilder addDrawerItems(@NonNull IDrawerItem... drawerItems) {
this.getItemAdapter().add(drawerItems);
return this;
}
// defines if we want to keep the sticky items visible, upon switching to the profiles
protected boolean mKeepStickyItemsVisible = false;
/**
* Toggles if the sticky footer should stay visible upon switching to the profile list
* **WARNING** using this with stickyDrawerItems can lead to the selection not being updated correctly. Use with care
*
* @param keepStickyItemsVisible true if the sticky footer should stay visible
* @return this
*/
public DrawerBuilder withKeepStickyItemsVisible(boolean keepStickyItemsVisible) {
this.mKeepStickyItemsVisible = keepStickyItemsVisible;
return this;
}
// always visible list in drawer
protected List<IDrawerItem> mStickyDrawerItems = new ArrayList<>();
/**
* Set the initial List of IDrawerItems for the StickyDrawerFooter
*
* @param stickyDrawerItems
* @return
*/
public DrawerBuilder withStickyDrawerItems(@NonNull List<IDrawerItem> stickyDrawerItems) {
this.mStickyDrawerItems = stickyDrawerItems;
return this;
}
/**
* Add a initial DrawerItem or a DrawerItem Array for the StickyDrawerFooter
*
* @param stickyDrawerItems
* @return
*/
public DrawerBuilder addStickyDrawerItems(@NonNull IDrawerItem... stickyDrawerItems) {
if (this.mStickyDrawerItems == null) {
this.mStickyDrawerItems = new ArrayList<>();
}
Collections.addAll(this.mStickyDrawerItems, stickyDrawerItems);
return this;
}
/**
* Inflates the DrawerItems from a menu.xml
*
* @param menuRes
* @return
*/
public DrawerBuilder inflateMenu(@MenuRes int menuRes) {
MenuInflater menuInflater = new SupportMenuInflater(mActivity);
MenuBuilder mMenu = new MenuBuilder(mActivity);
menuInflater.inflate(menuRes, mMenu);
addMenuItems(mMenu, false);
return this;
}
/**
* helper method to init the drawerItems from a menu
*
* @param mMenu
* @param subMenu
*/
private void addMenuItems(Menu mMenu, boolean subMenu) {
int groupId = R.id.material_drawer_menu_default_group;
for (int i = 0; i < mMenu.size(); i++) {
MenuItem mMenuItem = mMenu.getItem(i);
IDrawerItem iDrawerItem;
if (!subMenu && mMenuItem.getGroupId() != groupId && mMenuItem.getGroupId() != 0) {
groupId = mMenuItem.getGroupId();
iDrawerItem = new DividerDrawerItem();
getItemAdapter().add(iDrawerItem);
}
if (mMenuItem.hasSubMenu()) {
iDrawerItem = new PrimaryDrawerItem()
.withName(mMenuItem.getTitle().toString())
.withIcon(mMenuItem.getIcon())
.withIdentifier(mMenuItem.getItemId())
.withEnabled(mMenuItem.isEnabled())
.withSelectable(false);
getItemAdapter().add(iDrawerItem);
addMenuItems(mMenuItem.getSubMenu(), true);
} else if (mMenuItem.getGroupId() != 0 || subMenu) {
iDrawerItem = new SecondaryDrawerItem()
.withName(mMenuItem.getTitle().toString())
.withIcon(mMenuItem.getIcon())
.withIdentifier(mMenuItem.getItemId())
.withEnabled(mMenuItem.isEnabled());
getItemAdapter().add(iDrawerItem);
} else {
iDrawerItem = new PrimaryDrawerItem()
.withName(mMenuItem.getTitle().toString())
.withIcon(mMenuItem.getIcon())
.withIdentifier(mMenuItem.getItemId())
.withEnabled(mMenuItem.isEnabled());
getItemAdapter().add(iDrawerItem);
}
}
}
// close drawer on click
protected boolean mCloseOnClick = true;
/**
* Set this to false if the drawer should stay opened after an item was clicked
*
* @param closeOnClick
* @return this
*/
public DrawerBuilder withCloseOnClick(boolean closeOnClick) {
this.mCloseOnClick = closeOnClick;
return this;
}
// delay drawer close to prevent lag
protected int mDelayOnDrawerClose = 50;
/**
* Define the delay for the drawer close operation after a click.
* This is a small trick to improve the speed (and remove lag) if you open a new activity after a DrawerItem
* was selected.
* NOTE: Disable this by passing -1
*
* @param delayOnDrawerClose the delay in MS (-1 to disable)
* @return this
*/
public DrawerBuilder withDelayOnDrawerClose(int delayOnDrawerClose) {
this.mDelayOnDrawerClose = delayOnDrawerClose;
return this;
}
// delay drawer click event to prevent lag (you should either choose DelayOnDrawerClose or this)
protected int mDelayDrawerClickEvent = 0;
/**
* Define the delay for the drawer click event after a click.
* This can be used to improve performance and prevent lag, especially when you switch fragments inside the listener.
* This will ignore the boolean value you can return in the listener, as the listener is called after the drawer was closed.
* NOTE: Disable this to pass -1
*
* @param delayDrawerClickEvent -1 to disable
* @return this
*/
public DrawerBuilder withDelayDrawerClickEvent(int delayDrawerClickEvent) {
this.mDelayDrawerClickEvent = delayDrawerClickEvent;
return this;
}
// onDrawerListener
protected Drawer.OnDrawerListener mOnDrawerListener;
/**
* Define a OnDrawerListener for this Drawer
*
* @param onDrawerListener
* @return this
*/
public DrawerBuilder withOnDrawerListener(@NonNull Drawer.OnDrawerListener onDrawerListener) {
this.mOnDrawerListener = onDrawerListener;
return this;
}
// onDrawerItemClickListeners
protected Drawer.OnDrawerItemClickListener mOnDrawerItemClickListener;
/**
* Define a OnDrawerItemClickListener for this Drawer
*
* @param onDrawerItemClickListener
* @return
*/
public DrawerBuilder withOnDrawerItemClickListener(@NonNull Drawer.OnDrawerItemClickListener onDrawerItemClickListener) {
this.mOnDrawerItemClickListener = onDrawerItemClickListener;
return this;
}
// onDrawerItemClickListeners
protected Drawer.OnDrawerItemLongClickListener mOnDrawerItemLongClickListener;
/**
* Define a OnDrawerItemLongClickListener for this Drawer
*
* @param onDrawerItemLongClickListener
* @return
*/
public DrawerBuilder withOnDrawerItemLongClickListener(@NonNull Drawer.OnDrawerItemLongClickListener onDrawerItemLongClickListener) {
this.mOnDrawerItemLongClickListener = onDrawerItemLongClickListener;
return this;
}
// onDrawerListener
protected Drawer.OnDrawerNavigationListener mOnDrawerNavigationListener;
/**
* Define a OnDrawerNavigationListener for this Drawer
*
* @param onDrawerNavigationListener
* @return this
*/
public DrawerBuilder withOnDrawerNavigationListener(@NonNull Drawer.OnDrawerNavigationListener onDrawerNavigationListener) {
this.mOnDrawerNavigationListener = onDrawerNavigationListener;
return this;
}
//show the drawer on the first launch to show the user its there
protected boolean mShowDrawerOnFirstLaunch = false;
/**
* define if the DrawerBuilder is shown on the first launch
*
* @param showDrawerOnFirstLaunch
* @return
*/
public DrawerBuilder withShowDrawerOnFirstLaunch(boolean showDrawerOnFirstLaunch) {
this.mShowDrawerOnFirstLaunch = showDrawerOnFirstLaunch;
return this;
}
//show the drawer on launch to show the user its there, keep doing it until the user has dragged it open once
protected boolean mShowDrawerUntilDraggedOpened = false;
/**
* define if the DrawerBuilder is shown until the user has dragged it open once
*
* @param showDrawerUntilDraggedOpened
* @return DrawerBuilder
*/
public DrawerBuilder withShowDrawerUntilDraggedOpened(boolean showDrawerUntilDraggedOpened) {
mShowDrawerUntilDraggedOpened = showDrawerUntilDraggedOpened;
return this;
}
//also generate the MiniDrawer for this Drawer
protected boolean mGenerateMiniDrawer = false;
protected MiniDrawer mMiniDrawer = null;
/**
* define if the DrawerBuilder should also generate a MiniDrawer for th
*
* @param generateMiniDrawer
* @return
*/
public DrawerBuilder withGenerateMiniDrawer(boolean generateMiniDrawer) {
this.mGenerateMiniDrawer = generateMiniDrawer;
return this;
}
// savedInstance to restore state
protected Bundle mSavedInstance;
/**
* Set the Bundle (savedInstance) which is passed by the activity.
* No need to null-check everything is handled automatically
*
* @param savedInstance
* @return
*/
public DrawerBuilder withSavedInstance(Bundle savedInstance) {
this.mSavedInstance = savedInstance;
return this;
}
// shared preferences to use for integrated functions
protected SharedPreferences mSharedPreferences;
/**
* Set the {@link SharedPreferences} to use for the `showDrawerOnFirstLaunch` or the `ShowDrawerUntilDraggedOpened`
*
* @param sharedPreferences SharedPreference to use
* @return this
*/
public DrawerBuilder withSharedPreferences(SharedPreferences sharedPreferences) {
this.mSharedPreferences = sharedPreferences;
return this;
}
/**
* helper method to handle when the drawer should be shown on launch
*/
private void handleShowOnLaunch() {
//check if it should be shown on launch (and we have a drawerLayout)
if (mActivity != null && mDrawerLayout != null) {
if (mShowDrawerOnFirstLaunch || mShowDrawerUntilDraggedOpened) {
final SharedPreferences preferences = mSharedPreferences != null ? mSharedPreferences : PreferenceManager.getDefaultSharedPreferences(mActivity);
if (mShowDrawerOnFirstLaunch && !preferences.getBoolean(Drawer.PREF_USER_LEARNED_DRAWER, false)) {
//if it was not shown yet
//open the drawer
mDrawerLayout.openDrawer(mSliderLayout);
//save that it showed up once ;)
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean(Drawer.PREF_USER_LEARNED_DRAWER, true);
editor.apply();
} else if (mShowDrawerUntilDraggedOpened && !preferences.getBoolean(Drawer.PREF_USER_OPENED_DRAWER_BY_DRAGGING, false)) {
// open the drawer since the user has not dragged it open yet
mDrawerLayout.openDrawer(mSliderLayout);
// add a listener to detect dragging
mDrawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
boolean hasBeenDragged = false;
@Override
public void onDrawerStateChanged(int newState) {
if (newState == DrawerLayout.STATE_DRAGGING) {
// save that the user was dragging
hasBeenDragged = true;
} else if (newState == DrawerLayout.STATE_IDLE) {
// check if the user was dragging and if that resulted in an open drawer
if (hasBeenDragged && mDrawerLayout.isDrawerOpen(mDrawerGravity)) {
// Save that the user has dragged it open
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean(Drawer.PREF_USER_OPENED_DRAWER_BY_DRAGGING, true);
editor.apply();
} else {
// reset the drag boolean
hasBeenDragged = false;
}
}
}
});
}
}
}
}
/**
* Build and add the DrawerBuilder to your activity
*
* @return
*/
public Drawer build() {
if (mUsed) {
throw new RuntimeException("you must not reuse a DrawerBuilder builder");
}
if (mActivity == null) {
throw new RuntimeException("please pass an activity");
}
//set that this builder was used. now you have to create a new one
mUsed = true;
// if the user has not set a drawerLayout use the default one :D
if (mDrawerLayout == null) {
withDrawerLayout(-1);
}
//some new Materialize magic ;)
mMaterialize = new MaterializeBuilder()
.withActivity(mActivity)
.withRootView(mRootView)
.withFullscreen(mFullscreen)
.withSystemUIHidden(mSystemUIHidden)
.withUseScrimInsetsLayout(false)
.withTransparentStatusBar(mTranslucentStatusBar)
.withTranslucentNavigationBarProgrammatically(mTranslucentNavigationBarProgrammatically)
.withContainer(mDrawerLayout)
.build();
//handle the navigation stuff of the ActionBarDrawerToggle and the drawer in general
handleDrawerNavigation(mActivity, false);
//build the view which will be set to the drawer
Drawer result = buildView();
//define id for the sliderLayout
mSliderLayout.setId(R.id.material_drawer_slider_layout);
// add the slider to the drawer
mDrawerLayout.addView(mSliderLayout, 1);
return result;
}
/**
* Build and add the DrawerBuilder to your activity
*
* @return
*/
public Drawer buildForFragment() {
if (mUsed) {
throw new RuntimeException("you must not reuse a DrawerBuilder builder");
}
if (mActivity == null) {
throw new RuntimeException("please pass an activity");
}
if (mRootView == null) {
throw new RuntimeException("please pass the view which should host the DrawerLayout");
}
//set that this builder was used. now you have to create a new one
mUsed = true;
// if the user has not set a drawerLayout use the default one :D
if (mDrawerLayout == null) {
withDrawerLayout(-1);
}
//set the drawer here...
View originalContentView = mRootView.getChildAt(0);
boolean alreadyInflated = originalContentView.getId() == R.id.materialize_root;
//only add the new layout if it wasn't done before
if (!alreadyInflated) {
// remove the contentView
mRootView.removeView(originalContentView);
} else {
//if it was already inflated we have to clean up again
mRootView.removeAllViews();
}
//create the layoutParams to use for the contentView
FrameLayout.LayoutParams layoutParamsContentView = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
//add the drawer
mRootView.addView(mDrawerLayout, layoutParamsContentView);
//set the id so we can check if it was already inflated
mDrawerLayout.setId(R.id.materialize_root);
//handle the navigation stuff of the ActionBarDrawerToggle and the drawer in general
handleDrawerNavigation(mActivity, false);
//build the view which will be set to the drawer
Drawer result = buildView();
// add the slider to the drawer
mDrawerLayout.addView(originalContentView, 0);
//define id for the sliderLayout
mSliderLayout.setId(R.id.material_drawer_slider_layout);
// add the slider to the drawer
mDrawerLayout.addView(mSliderLayout, 1);
return result;
}
/**
* handles the different logics for the Drawer Navigation Listeners / Indications (ActionBarDrawertoggle)
*/
protected void handleDrawerNavigation(Activity activity, boolean recreateActionBarDrawerToggle) {
//set the navigationOnClickListener
final View.OnClickListener toolbarNavigationListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean handled = false;
if (mOnDrawerNavigationListener != null && (mActionBarDrawerToggle != null && !mActionBarDrawerToggle.isDrawerIndicatorEnabled())) {
handled = mOnDrawerNavigationListener.onNavigationClickListener(v);
}
if (!handled) {
if (mDrawerLayout.isDrawerOpen(mDrawerGravity)) {
mDrawerLayout.closeDrawer(mDrawerGravity);
} else {
mDrawerLayout.openDrawer(mDrawerGravity);
}
}
}
};
if (recreateActionBarDrawerToggle) {
mActionBarDrawerToggle = null;
}
// create the ActionBarDrawerToggle if not set and enabled and if we have a toolbar
if (mActionBarDrawerToggleEnabled && mActionBarDrawerToggle == null && mToolbar != null) {
this.mActionBarDrawerToggle = new ActionBarDrawerToggle(activity, mDrawerLayout, mToolbar, R.string.material_drawer_open, R.string.material_drawer_close) {
@Override
public void onDrawerOpened(View drawerView) {
if (mOnDrawerListener != null) {
mOnDrawerListener.onDrawerOpened(drawerView);
}
super.onDrawerOpened(drawerView);
}
@Override
public void onDrawerClosed(View drawerView) {
if (mOnDrawerListener != null) {
mOnDrawerListener.onDrawerClosed(drawerView);
}
super.onDrawerClosed(drawerView);
}
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
if (mOnDrawerListener != null) {
mOnDrawerListener.onDrawerSlide(drawerView, slideOffset);
}
if (!mAnimateActionBarDrawerToggle) {
super.onDrawerSlide(drawerView, 0);
} else {
super.onDrawerSlide(drawerView, slideOffset);
}
}
};
this.mActionBarDrawerToggle.syncState();
}
//if we got a toolbar set a toolbarNavigationListener
//we also have to do this after setting the ActionBarDrawerToggle as this will overwrite this
if (mToolbar != null) {
this.mToolbar.setNavigationOnClickListener(toolbarNavigationListener);
}
//handle the ActionBarDrawerToggle
if (mActionBarDrawerToggle != null) {
mActionBarDrawerToggle.setToolbarNavigationClickListener(toolbarNavigationListener);
mDrawerLayout.addDrawerListener(mActionBarDrawerToggle);
} else {
mDrawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
if (mOnDrawerListener != null) {
mOnDrawerListener.onDrawerSlide(drawerView, slideOffset);
}
}
@Override
public void onDrawerOpened(View drawerView) {
if (mOnDrawerListener != null) {
mOnDrawerListener.onDrawerOpened(drawerView);
}
}
@Override
public void onDrawerClosed(View drawerView) {
if (mOnDrawerListener != null) {
mOnDrawerListener.onDrawerClosed(drawerView);
}
}
@Override
public void onDrawerStateChanged(int newState) {
}
});
}
}
/**
* build the drawers content only. This will still return a Result object, but only with the content set. No inflating of a DrawerLayout.
*
* @return Result object with only the content set
*/
public Drawer buildView() {
// get the slider view
mSliderLayout = (ScrimInsetsRelativeLayout) mActivity.getLayoutInflater().inflate(R.layout.material_drawer_slider, mDrawerLayout, false);
mSliderLayout.setBackgroundColor(UIUtils.getThemeColorFromAttrOrRes(mActivity, R.attr.material_drawer_background, R.color.material_drawer_background));
// get the layout params
DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) mSliderLayout.getLayoutParams();
if (params != null) {
// if we've set a custom gravity set it
params.gravity = mDrawerGravity;
// if this is a drawer from the right, change the margins :D
params = DrawerUtils.processDrawerLayoutParams(this, params);
// set the new layout params
mSliderLayout.setLayoutParams(params);
}
//create the content
createContent();
//create the result object
Drawer result = new Drawer(this);
//set the drawer for the accountHeader if set
if (mAccountHeader != null) {
mAccountHeader.setDrawer(result);
}
//toggle selection list if we were previously on the account list
if (mSavedInstance != null && mSavedInstance.getBoolean(Drawer.BUNDLE_DRAWER_CONTENT_SWITCHED, false)) {
mAccountHeader.toggleSelectionList(mActivity);
}
//handle if the drawer should be shown on launch
handleShowOnLaunch();
//we only want to hook a Drawer to the MiniDrawer if it is the main drawer, not the appended one
if (!mAppended && mGenerateMiniDrawer) {
// if we should create a MiniDrawer we have to do this now
mMiniDrawer = new MiniDrawer().withDrawer(result).withAccountHeader(mAccountHeader);
}
//forget the reference to the activity
mActivity = null;
return result;
}
/**
* Call this method to append a new DrawerBuilder to a existing Drawer.
*
* @param result the Drawer.Result of an existing Drawer
* @return
*/
public Drawer append(@NonNull Drawer result) {
if (mUsed) {
throw new RuntimeException("you must not reuse a DrawerBuilder builder");
}
if (mDrawerGravity == null) {
throw new RuntimeException("please set the gravity for the drawer");
}
//set that this builder was used. now you have to create a new one
mUsed = true;
mAppended = true;
//get the drawer layout from the previous drawer
mDrawerLayout = result.getDrawerLayout();
// get the slider view
mSliderLayout = (ScrimInsetsRelativeLayout) mActivity.getLayoutInflater().inflate(R.layout.material_drawer_slider, mDrawerLayout, false);
mSliderLayout.setBackgroundColor(UIUtils.getThemeColorFromAttrOrRes(mActivity, R.attr.material_drawer_background, R.color.material_drawer_background));
// get the layout params
DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) mSliderLayout.getLayoutParams();
// set the gravity of this drawerGravity
params.gravity = mDrawerGravity;
// if this is a drawer from the right, change the margins :D
params = DrawerUtils.processDrawerLayoutParams(this, params);
// set the new params
mSliderLayout.setLayoutParams(params);
//define id for the sliderLayout
mSliderLayout.setId(R.id.material_drawer_slider_layout);
// add the slider to the drawer
mDrawerLayout.addView(mSliderLayout, 1);
//create the content
createContent();
//create the result object
Drawer appendedResult = new Drawer(this);
//toggle selection list if we were previously on the account list
if (mSavedInstance != null && mSavedInstance.getBoolean(Drawer.BUNDLE_DRAWER_CONTENT_SWITCHED_APPENDED, false)) {
mAccountHeader.toggleSelectionList(mActivity);
}
//forget the reference to the activity
mActivity = null;
return appendedResult;
}
/**
* the helper method to create the content for the drawer
*/
private void createContent() {
//if we have a customView use this
if (mCustomView != null) {
LinearLayout.LayoutParams contentParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
contentParams.weight = 1f;
mSliderLayout.addView(mCustomView, contentParams);
return;
}
//set the shadow for the drawer
if (Build.VERSION.SDK_INT < 21 && mDrawerLayout != null) {
if (ViewCompat.getLayoutDirection(mRootView) == ViewCompat.LAYOUT_DIRECTION_LTR) {
mDrawerLayout.setDrawerShadow(mDrawerGravity == GravityCompat.START ? R.drawable.material_drawer_shadow_right : R.drawable.material_drawer_shadow_left, mDrawerGravity);
} else {
mDrawerLayout.setDrawerShadow(mDrawerGravity == GravityCompat.START ? R.drawable.material_drawer_shadow_left : R.drawable.material_drawer_shadow_right, mDrawerGravity);
}
}
// if we have an adapter (either by defining a custom one or the included one add a list :D
View contentView;
if (mRecyclerView == null) {
contentView = LayoutInflater.from(mActivity).inflate(R.layout.material_drawer_recycler_view, mSliderLayout, false);
mRecyclerView = (RecyclerView) contentView.findViewById(R.id.material_drawer_recycler_view);
//set the itemAnimator
mRecyclerView.setItemAnimator(mItemAnimator);
//some style improvements on older devices
mRecyclerView.setFadingEdgeLength(0);
//set the drawing cache background to the same color as the slider to improve performance
//mRecyclerView.setDrawingCacheBackgroundColor(UIUtils.getThemeColorFromAttrOrRes(mActivity, R.attr.material_drawer_background, R.color.material_drawer_background));
mRecyclerView.setClipToPadding(false);
//additional stuff
mRecyclerView.setLayoutManager(mLayoutManager);
int paddingTop = 0;
if ((mDisplayBelowStatusBar == null || mDisplayBelowStatusBar) && !mSystemUIHidden) {
paddingTop = UIUtils.getStatusBarHeight(mActivity);
}
int paddingBottom = 0;
int orientation = mActivity.getResources().getConfiguration().orientation;
if (((mTranslucentNavigationBar || mFullscreen) && Build.VERSION.SDK_INT >= 21) && !mSystemUIHidden
&& (orientation == Configuration.ORIENTATION_PORTRAIT
|| (orientation == Configuration.ORIENTATION_LANDSCAPE
&& DrawerUIUtils.isSystemBarOnBottom(mActivity)))) {
paddingBottom = UIUtils.getNavigationBarHeight(mActivity);
}
mRecyclerView.setPadding(0, paddingTop, 0, paddingBottom);
} else {
contentView = mRecyclerView;
}
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
params.weight = 1f;
mSliderLayout.addView(contentView, params);
if (mInnerShadow) {
View innerShadow = mSliderLayout.findViewById(R.id.material_drawer_inner_shadow);
innerShadow.setVisibility(View.VISIBLE);
innerShadow.bringToFront();
if (mDrawerGravity == GravityCompat.START) {
innerShadow.setBackgroundResource(R.drawable.material_drawer_shadow_left);
} else {
innerShadow.setBackgroundResource(R.drawable.material_drawer_shadow_right);
}
}
// set the background
if (mSliderBackgroundColor != 0) {
mSliderLayout.setBackgroundColor(mSliderBackgroundColor);
} else if (mSliderBackgroundColorRes != -1) {
mSliderLayout.setBackgroundColor(ContextCompat.getColor(mActivity, mSliderBackgroundColorRes));
} else if (mSliderBackgroundDrawable != null) {
UIUtils.setBackground(mSliderLayout, mSliderBackgroundDrawable);
} else if (mSliderBackgroundDrawableRes != -1) {
UIUtils.setBackground(mSliderLayout, mSliderBackgroundDrawableRes);
}
//handle the header
DrawerUtils.handleHeaderView(this);
//handle the footer
DrawerUtils.handleFooterView(this, new View.OnClickListener() {
@Override
public void onClick(View v) {
IDrawerItem drawerItem = (IDrawerItem) v.getTag(R.id.material_drawer_item);
DrawerUtils.onFooterDrawerItemClick(DrawerBuilder.this, drawerItem, v, true);
}
});
//if MultiSelect is possible
mAdapter.withMultiSelect(mMultiSelect);
if (mMultiSelect) {
mAdapter.withSelectOnLongClick(false);
mAdapter.withAllowDeselection(true);
}
//set the adapter on the listView
if (mAdapterWrapper == null) {
mRecyclerView.setAdapter(mAdapter);
} else {
mRecyclerView.setAdapter(mAdapterWrapper);
}
//predefine selection (should be the first element
if (mSelectedItemPosition == 0 && mSelectedItemIdentifier != 0L) {
mSelectedItemPosition = DrawerUtils.getPositionByIdentifier(this, mSelectedItemIdentifier);
}
if (mHeaderView != null && mSelectedItemPosition == 0) {
mSelectedItemPosition = 1;
}
mAdapter.deselect();
mAdapter.select(mSelectedItemPosition);
// add the onDrawerItemClickListener if set
mAdapter.withOnClickListener(new OnClickListener<IDrawerItem>() {
@Override
public boolean onClick(final View view, IAdapter<IDrawerItem> adapter, final IDrawerItem item, final int position) {
if (!(item != null && item instanceof Selectable && !item.isSelectable())) {
resetStickyFooterSelection();
mCurrentStickyFooterSelection = -1;
}
//call the listener
boolean consumed = false;
//call the item specific listener
if (item instanceof AbstractDrawerItem && ((AbstractDrawerItem) item).getOnDrawerItemClickListener() != null) {
consumed = ((AbstractDrawerItem) item).getOnDrawerItemClickListener().onItemClick(view, position, item);
}
//call the drawer listener
if (mOnDrawerItemClickListener != null) {
if (mDelayDrawerClickEvent > 0) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mOnDrawerItemClickListener.onItemClick(view, position, item);
}
}, mDelayDrawerClickEvent);
} else {
consumed = mOnDrawerItemClickListener.onItemClick(view, position, item);
}
}
//we have to notify the miniDrawer if existing, and if the event was not consumed yet
if (!consumed && mMiniDrawer != null) {
consumed = mMiniDrawer.onItemClick(item);
}
//if we were a expandable item we consume the event closing makes no sense
if (item instanceof IExpandable && ((IExpandable) item).getSubItems() != null) {
//we consume the event and want no further handling
return true;
}
if (!consumed) {
//close the drawer after click
closeDrawerDelayed();
}
return consumed;
}
});
// add the onDrawerItemLongClickListener if set
mAdapter.withOnLongClickListener(new OnLongClickListener<IDrawerItem>() {
@Override
public boolean onLongClick(View view, IAdapter<IDrawerItem> adapter, final IDrawerItem item, final int position) {
if (mOnDrawerItemLongClickListener != null) {
return mOnDrawerItemLongClickListener.onItemLongClick(view, position, getDrawerItem(position));
}
return false;
}
});
if (mRecyclerView != null) {
mRecyclerView.scrollToPosition(0);
}
// try to restore all saved values again
if (mSavedInstance != null) {
if (!mAppended) {
mAdapter.deselect();
mAdapter.withSavedInstanceState(mSavedInstance, Drawer.BUNDLE_SELECTION);
DrawerUtils.setStickyFooterSelection(this, mSavedInstance.getInt(Drawer.BUNDLE_STICKY_FOOTER_SELECTION, -1), null);
} else {
mAdapter.deselect();
mAdapter.withSavedInstanceState(mSavedInstance, Drawer.BUNDLE_SELECTION_APPENDED);
DrawerUtils.setStickyFooterSelection(this, mSavedInstance.getInt(Drawer.BUNDLE_STICKY_FOOTER_SELECTION_APPENDED, -1), null);
}
}
// call initial onClick event to allow the dev to init the first view
if (mFireInitialOnClick && mOnDrawerItemClickListener != null) {
int selection = mAdapter.getSelections().size() == 0 ? -1 : mAdapter.getSelections().iterator().next();
mOnDrawerItemClickListener.onItemClick(null, selection, getDrawerItem(selection));
}
}
/**
* helper method to close the drawer delayed
*/
protected void closeDrawerDelayed() {
if (mCloseOnClick && mDrawerLayout != null) {
if (mDelayOnDrawerClose > -1) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mDrawerLayout.closeDrawers();
if (mScrollToTopAfterClick) {
mRecyclerView.smoothScrollToPosition(0);
}
}
}, mDelayOnDrawerClose);
} else {
mDrawerLayout.closeDrawers();
}
}
}
/**
* get the drawerItem at a specific position
*
* @param position
* @return
*/
protected IDrawerItem getDrawerItem(int position) {
return (IDrawerItem) getAdapter().getItem(position);
}
/**
* check if the item is within the bounds of the list
*
* @param position
* @param includeOffset
* @return
*/
protected boolean checkDrawerItem(int position, boolean includeOffset) {
return getAdapter().getItem(position) != null;
}
/**
* simple helper method to reset the selection of the sticky footer
*/
protected void resetStickyFooterSelection() {
if (mStickyFooterView instanceof LinearLayout) {
for (int i = 0; i < (mStickyFooterView).getChildCount(); i++) {
(mStickyFooterView).getChildAt(i).setActivated(false);
(mStickyFooterView).getChildAt(i).setSelected(false);
}
}
}
}