com.github.rubensousa.navigationmanager.NavigationManager.java Source code

Java tutorial

Introduction

Here is the source code for com.github.rubensousa.navigationmanager.NavigationManager.java

Source

/*
 * Copyright 2016 Rben Sousa
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.rubensousa.navigationmanager;

import android.annotation.SuppressLint;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.MenuItem;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.View;

public abstract class NavigationManager
        implements NavigationView.OnNavigationItemSelectedListener, DrawerLayout.DrawerListener {

    public static final String NAVIGATE_ID = "navigate_id";
    public static final String CURRENT_ID = "current_id";
    public static final String CURRENT_TITLE = "current_title";
    public static final String ACTION_MODE_SUSPENDED = "action_mode_state";
    public static final String ACTION_MODE_ACTIVE = "action_mode_active";

    private NavigationView mNavigationView;
    private DrawerLayout mDrawerLayout;
    private NavigationListener mNavigationListener;
    private ActionModeListener mActionModeListener;
    private FragmentTransaction mFragmentTransaction;
    private FragmentManager mFragmentManager;
    private Intent mIntent;
    private Fragment mCurrentFragment;
    private int mContainerId;
    private int mCurrentId;
    private String mTitle;
    private boolean mNavigating;

    public NavigationManager(FragmentManager fragmentManager, NavigationView navigationView,
            DrawerLayout drawerLayout, @IdRes int containerId) {
        mFragmentManager = fragmentManager;
        mNavigationView = navigationView;
        mDrawerLayout = drawerLayout;
        mContainerId = containerId;
        mDrawerLayout.addDrawerListener(this);
        mNavigationView.setNavigationItemSelectedListener(this);
    }

    public void init(Bundle savedInstanceState, Intent intent) {
        if (savedInstanceState != null) {
            mCurrentId = savedInstanceState.getInt(CURRENT_ID);
            mTitle = savedInstanceState.getString(CURRENT_TITLE);
            mCurrentFragment = mFragmentManager.findFragmentByTag(CURRENT_TITLE);
        } else {
            mIntent = intent;
            if (mIntent == null) {
                navigate(getDefaultItem());
            } else {
                Bundle args = mIntent.getExtras();
                if (args != null) {
                    int menuId = args.getInt(NAVIGATE_ID);
                    MenuItem item = mNavigationView.getMenu().findItem(menuId);
                    if (item != null && menuId != 0) {
                        onNavigationItemSelected(item);
                    } else { // If the intent doesn't have a valid navigate id, open default item
                        navigate(getDefaultItem());
                    }
                } else { // If the intent doesn't have extras, navigate to the default item
                    navigate(getDefaultItem());
                }
            }
        }
    }

    public void onSaveInstanceState(Bundle outState) {
        outState.putInt(CURRENT_ID, mCurrentId);
        outState.putString(CURRENT_TITLE, mTitle);
    }

    public boolean shouldDelayTransaction(int item) {
        return true;
    }

    public abstract int getDefaultItem();

    @NonNull
    public abstract Fragment createFragment(@IdRes int item);

    /**
     * Navigate via Intent. The intent must contain a NAVIGATE_ID field with the menu id of the
     * section desired to navigate to.
     *
     * @param intent Intent to be passed to the new fragment
     */
    public void navigateWithIntent(Intent intent) {
        mIntent = intent;
        if (mIntent != null) {
            Bundle args = mIntent.getExtras();
            if (args != null) {
                int menuId = args.getInt(NAVIGATE_ID);
                navigate(menuId);
            }
        }
    }

    public void navigate(@IdRes int menuId) {
        if (mCurrentId != menuId) {
            MenuItem newItem = mNavigationView.getMenu().findItem(menuId);
            if (newItem != null) {
                MenuItem lastItem = mNavigationView.getMenu().findItem(mCurrentId);
                if (lastItem != null) {
                    lastItem.setChecked(false);
                }
                mNavigating = true;
                onNavigationItemSelected(newItem);
            }
        }
    }

    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        if (mNavigationListener != null) {
            mNavigationListener.onItemSelected(item);
        }

        closeDrawer();
        boolean firstStart = mCurrentId == 0;

        if (item.getItemId() == mCurrentId) {
            mNavigating = false;
            return false;
        }

        mCurrentId = item.getItemId();
        mTitle = item.getTitle().toString();

        // If an item is checkable, then a fragment should be used
        if (item.isCheckable()) {
            mNavigationView.setCheckedItem(mCurrentId);

            if (mNavigationListener != null && mCurrentFragment != null) {
                mNavigationListener.onSectionChange(mCurrentFragment);
            }

            mCurrentFragment = createFragment(item.getItemId());

            // Check if we have an Intent to pass to the fragment
            if (mIntent != null) {
                Bundle args = mCurrentFragment.getArguments();
                Bundle extras = mIntent.getExtras();

                // If no arguments were passed to the fragment, the bundle must be created
                if (args == null) {
                    args = new Bundle();
                }

                // Add the fragment's arguments to the new Intent
                if (extras != null) {
                    args.putAll(extras);
                }

                mCurrentFragment.setArguments(args);
                mIntent = null;
            }

            if (!shouldDelayTransaction(mCurrentId) || firstStart || mNavigating) {
                commitFragmentTransaction(createFragmentTransaction(mCurrentFragment));
            } else {
                mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
                mFragmentTransaction = createFragmentTransaction(mCurrentFragment);
            }
            mNavigating = false;
            return true;
        }

        mNavigating = false;
        return false;
    }

    @Override
    public void onDrawerSlide(View drawerView, float slideOffset) {

        if (slideOffset == 0) {
            onDrawerClosed(drawerView);
        } else {
            onDrawerOpened(drawerView);
        }
    }

    @Override
    public void onDrawerOpened(View drawerView) {

        if (mActionModeListener != null && mActionModeListener.isActionModeActive()) {
            mActionModeListener.onSuspendActionMode();
        }

        if (mCurrentFragment instanceof ActionModeListener) {
            ActionModeListener fragCallbacks = ((ActionModeListener) mCurrentFragment);

            if (fragCallbacks.isActionModeActive()) {
                fragCallbacks.onSuspendActionMode();
            }
        }
    }

    @Override
    public void onDrawerClosed(View drawerView) {

        if (mActionModeListener != null && mActionModeListener.isActionModeSuspended()) {
            mActionModeListener.onResumeActionMode();
        }

        if (mCurrentFragment instanceof ActionModeListener) {
            ActionModeListener fragCallbacks = ((ActionModeListener) mCurrentFragment);

            if (fragCallbacks.isActionModeSuspended()) {
                fragCallbacks.onResumeActionMode();
            }
        }

        if (mFragmentTransaction != null && shouldDelayTransaction(mCurrentId)) {
            commitFragmentTransaction(mFragmentTransaction);
            mFragmentTransaction = null;
            mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
        }
    }

    @Override
    public void onDrawerStateChanged(int newState) {

    }

    public Fragment getCurrentFragment() {
        return mCurrentFragment;
    }

    public int getCurrentId() {
        return mCurrentId;
    }

    public String getCurrentTitle() {
        return mTitle;
    }

    public void setActionModeListener(ActionModeListener actionModeListener) {
        mActionModeListener = actionModeListener;
    }

    public void setNavigationListener(NavigationListener navigationListener) {
        mNavigationListener = navigationListener;
    }

    @SuppressLint("CommitTransaction")
    public FragmentTransaction createFragmentTransaction(Fragment fragment) {
        return mFragmentManager.beginTransaction().replace(mContainerId, fragment, CURRENT_TITLE);
    }

    public void commitFragmentTransaction(FragmentTransaction transaction) {
        // We can allow state loss because the fragment will start for the first time
        transaction.commitAllowingStateLoss();
    }

    public boolean openDrawer() {
        if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
            return false;
        }
        mDrawerLayout.openDrawer(GravityCompat.START);
        return true;
    }

    public boolean closeDrawer() {
        if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
            mDrawerLayout.closeDrawer(GravityCompat.START);
            return true;
        }
        return false;
    }

    public static void saveActionModeState(Bundle outState, ActionModeListener callbacks) {
        outState.putBoolean(ACTION_MODE_SUSPENDED, callbacks.isActionModeSuspended());
        outState.putBoolean(ACTION_MODE_ACTIVE, callbacks.isActionModeActive());
    }

    public static Intent createNavigationIntent(@IdRes int res) {
        Intent intent = new Intent();
        intent.putExtra(NAVIGATE_ID, res);
        return intent;
    }

    public interface NavigationListener {
        void onItemSelected(MenuItem item);

        void onSectionChange(Fragment currentFragment);
    }

    public interface ActionModeListener {
        void onSuspendActionMode();

        void onResumeActionMode();

        boolean isActionModeActive();

        boolean isActionModeSuspended();
    }

}