com.shalzz.attendance.activity.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.shalzz.attendance.activity.MainActivity.java

Source

/*
 * Copyright (c) 2013-2016 Shaleen Jain <shaleen.jain95@gmail.com>
 *
 * This file is part of UPES Academics.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.shalzz.attendance.activity;

import android.animation.ValueAnimator;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.NavigationView;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.TextView;

import com.bugsnag.android.Bugsnag;
import com.github.amlcurran.showcaseview.ShowcaseView;
import com.github.amlcurran.showcaseview.targets.Target;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
import com.shalzz.attendance.BuildConfig;
import com.shalzz.attendance.DatabaseHandler;
import com.shalzz.attendance.Miscellaneous;
import com.shalzz.attendance.R;
import com.shalzz.attendance.fragment.AttendanceListFragment;
import com.shalzz.attendance.fragment.SettingsFragment;
import com.shalzz.attendance.fragment.TimeTablePagerFragment;
import com.shalzz.attendance.model.remote.User;
import com.shalzz.attendance.wrapper.MyApplication;

import javax.inject.Inject;
import javax.inject.Named;

import butterknife.BindArray;
import butterknife.BindBool;
import butterknife.BindView;
import butterknife.ButterKnife;
import timber.log.Timber;

public class MainActivity extends AppCompatActivity {

    /**
     * Null on tablets
     */
    @Nullable
    @BindView(R.id.drawer_layout)
    DrawerLayout mDrawerLayout;

    @BindView(R.id.list_slidermenu)
    NavigationView mNavigationView;

    @BindView(R.id.toolbar)
    Toolbar mToolbar;

    /**
     * Drawer lock state. True for tablets, false otherwise .
     */
    @BindBool(R.bool.tablet_layout)
    boolean isTabletLayout;

    @BindArray(R.array.drawer_array)
    String[] mNavTitles;

    @Inject
    @Named("app")
    Tracker mTracker;

    /**
     * To prevent saving the drawer position when logging out.
     */
    public static boolean LOGGED_OUT = false;

    /**
     * Remember the position of the selected item.
     */
    public static final String PREFERENCE_ACTIVATED_FRAGMENT = "ACTIVATED_FRAGMENT2.2";

    public static final String FRAGMENT_TAG = "MainActivity.FRAGMENT";

    public static final String LAUNCH_FRAGMENT_EXTRA = BuildConfig.APPLICATION_ID + ".MainActivity.LAUNCH_FRAGMENT";

    private static final String PREVIOUS_FRAGMENT_TAG = "MainActivity.PREVIOUS_FRAGMENT";

    public boolean mPopSettingsBackStack = false;

    private int mCurrentSelectedPosition = Fragments.ATTENDANCE.getValue();
    private ActionBarDrawerToggle mDrawerToggle;
    private DrawerHeaderViewHolder DrawerheaderVH;
    private FragmentManager mFragmentManager;
    private Fragment fragment = null;
    private DatabaseHandler mDb;
    // Our custom poor-man's back stack which has only one entry at maximum.
    private Fragment mPreviousFragment;

    public static class DrawerHeaderViewHolder extends RecyclerView.ViewHolder {
        @BindView(R.id.drawer_header_name)
        TextView tv_name;
        @BindView(R.id.drawer_header_course)
        TextView tv_course;
        @BindView(R.id.last_refreshed)
        TextView last_refresh;

        public DrawerHeaderViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        MyApplication.getAppComponent().inject(this);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.drawer);
        ButterKnife.bind(this);
        Bugsnag.setContext("MainActivity");

        mFragmentManager = getSupportFragmentManager();
        mDb = new DatabaseHandler(this);
        DrawerheaderVH = new DrawerHeaderViewHolder(mNavigationView.getHeaderView(0));

        setSupportActionBar(mToolbar);

        // Set the list's click listener
        mNavigationView.setNavigationItemSelectedListener(new NavigationItemSelectedListener());

        init(savedInstanceState);
    }

    @Override
    protected void onResume() {
        super.onResume();
        showcaseView();
    }

    @Override
    protected void onStart() {
        super.onStart();

        initDrawer();
    }

    /**
     * Initialise a fragment
     **/
    public void init(Bundle bundle) {

        // Select either the default item (Fragments.ATTENDANCE) or the last selected item.
        mCurrentSelectedPosition = reloadCurrentFragment();

        // Recycle fragment
        if (bundle != null) {
            fragment = mFragmentManager.findFragmentByTag(FRAGMENT_TAG);
            mPreviousFragment = mFragmentManager.getFragment(bundle, PREVIOUS_FRAGMENT_TAG);
            Timber.d("current fag found: %s", fragment);
            Timber.d("previous fag found: %s", mPreviousFragment);
            selectItem(mCurrentSelectedPosition);
            showFragment(fragment);
        } else {

            if (getIntent().hasExtra(LAUNCH_FRAGMENT_EXTRA)) {
                mCurrentSelectedPosition = getIntent().getIntExtra(LAUNCH_FRAGMENT_EXTRA,
                        Fragments.ATTENDANCE.getValue());
            } else if (getIntent().getAction() != null
                    && getIntent().getAction().equals(Intent.ACTION_MANAGE_NETWORK_USAGE)) {
                mCurrentSelectedPosition = Fragments.SETTINGS.getValue();
                Timber.i("MANAGE_NETWORK_USAGE intent received");
            }
            displayView(mCurrentSelectedPosition);
        }

        updateDrawerHeader();
    }

    private void initDrawer() {
        if (mDrawerLayout == null)
            return;

        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.drawer_open,
                R.string.drawer_close) {

            /** Called when a drawer has settled in a completely closed state. */
            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }

            /** Called when a drawer has settled in a completely open state. */
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }
        };
        mDrawerToggle.setDrawerIndicatorEnabled(true);
        mToolbar.setNavigationOnClickListener(v -> {
            int drawerLockMode = mDrawerLayout.getDrawerLockMode(GravityCompat.START);
            // check if drawer is shown as up
            if (drawerLockMode == DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
                onBackPressed();
            } else if (mDrawerLayout.isDrawerVisible(GravityCompat.START)
                    && (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_OPEN)) {
                mDrawerLayout.closeDrawer(GravityCompat.START);
            } else {
                mDrawerLayout.openDrawer(GravityCompat.START);
            }
        });
        mDrawerLayout.addDrawerListener(mDrawerToggle);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mDrawerLayout.setStatusBarBackgroundColor(getResources().getColor(R.color.primary_dark, getTheme()));
        } else {
            //noinspection deprecation
            mDrawerLayout.setStatusBarBackgroundColor(getResources().getColor(R.color.primary_dark));
        }
    }

    void showcaseView() {

        if (isTabletLayout) {
            if (fragment instanceof AttendanceListFragment) {
                ((AttendanceListFragment) fragment).showcaseView();
            }
            return;
        }

        Target homeTarget = () -> {
            // Get approximate position of home icon's center
            int actionBarSize = mToolbar.getHeight();
            int x = actionBarSize / 2;
            int y = actionBarSize / 2;
            return new Point(x, y);
        };

        final ShowcaseView sv = new ShowcaseView.Builder(this).setTarget(homeTarget).setStyle(R.style.ShowcaseTheme)
                .singleShot(1111).setContentTitle(getString(R.string.sv_main_activity_title))
                .setContentText(getString(R.string.sv_main_activity_content)).build();

        sv.overrideButtonClick(v -> {
            if (mDrawerLayout != null)
                mDrawerLayout.closeDrawer(mNavigationView);
            sv.hide();
            if (fragment instanceof AttendanceListFragment) {
                ((AttendanceListFragment) fragment).showcaseView();
            }
        });
    }

    public void updateDrawerHeader() {
        updateUserDetails();
        updateLastSync();
    }

    public void updateUserDetails() {
        if (mDb.getUserCount() > 0) {
            User user = mDb.getUser();

            DrawerheaderVH.tv_name.setText(user.name());
            DrawerheaderVH.tv_course.setText(user.course());
            Bugsnag.setUserId(user.sap_id());
            Bugsnag.setUserName(user.name());
            mTracker.set("&uid", user.sap_id());
            mTracker.send(new HitBuilders.ScreenViewBuilder()
                    .setCustomDimension(Miscellaneous.CUSTOM_DIMENSION_USER_ID, user.sap_id()).build());

        }
    }

    public void updateLastSync() {
        if (mDb.getSubjectCount() > 0) {
            int time = (int) mDb.getLastSync();
            DrawerheaderVH.last_refresh
                    .setText(getResources().getQuantityString(R.plurals.tv_last_refresh, time, time));
        }
    }

    public void setDrawerAsUp(boolean enabled) {
        if (mDrawerLayout == null)
            return;

        float start = enabled ? 0f : 1f;
        float end = enabled ? 1f : 0f;
        mDrawerLayout.setDrawerLockMode(
                enabled ? DrawerLayout.LOCK_MODE_LOCKED_CLOSED : DrawerLayout.LOCK_MODE_UNLOCKED);

        ValueAnimator anim = ValueAnimator.ofFloat(start, end);
        anim.addUpdateListener(valueAnimator -> {
            float slideOffset = (Float) valueAnimator.getAnimatedValue();
            mDrawerToggle.onDrawerSlide(mDrawerLayout, slideOffset);
        });
        anim.setInterpolator(new DecelerateInterpolator());
        anim.setDuration(300);
        anim.start();
    }

    private class NavigationItemSelectedListener implements NavigationView.OnNavigationItemSelectedListener {
        @Override
        public boolean onNavigationItemSelected(MenuItem menuItem) {
            displayView(menuItem.getOrder());
            return false;
        }
    }

    void displayView(int position) {
        ActionBar actionBar = getSupportActionBar();
        // update the main content by replacing fragments
        switch (position) {
        case 0:
            return;
        case 1:
            fragment = new AttendanceListFragment();
            mPreviousFragment = null; // GC
            if (isTabletLayout && actionBar != null) {
                actionBar.setDisplayHomeAsUpEnabled(false);
            }
            break;
        case 2:
            fragment = new TimeTablePagerFragment();
            mPreviousFragment = null; // GC
            if (isTabletLayout && actionBar != null) {
                actionBar.setDisplayHomeAsUpEnabled(false);
            }
            break;
        case 3:
            fragment = new SettingsFragment();
            if (isTabletLayout && actionBar != null) {
                actionBar.setDisplayHomeAsUpEnabled(true);
            }
            break;
        default:
            break;
        }

        if (fragment != null) {
            selectItem(position);
            showFragment(fragment);
        } else {
            Timber.e("Error in creating fragment");
        }
    }

    /**
     * Update selected item and title, then close the drawer
     * @param position the item to highlight
     */
    private void selectItem(int position) {
        mCurrentSelectedPosition = position;
        mNavigationView.getMenu().getItem(position - 1).setChecked(true);
        setTitle(mNavTitles[position - 1]);
        if (mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mNavigationView))
            mDrawerLayout.closeDrawer(mNavigationView);
    }

    /**
     * Push the installed fragment into our custom back stack (or optionally
     * {@link FragmentTransaction#remove} it) and {@link FragmentTransaction#add} {@code fragment}.
     *
     * @param fragment {@link Fragment} to be added.
     *
     */
    private void showFragment(Fragment fragment) {
        final FragmentTransaction ft = mFragmentManager.beginTransaction();
        final Fragment installed = getInstalledFragment();

        // return if the fragment is already installed
        if (isAttendanceListInstalled() && fragment instanceof AttendanceListFragment
                || isTimeTablePagerInstalled() && fragment instanceof TimeTablePagerFragment
                || isSettingsInstalled() && fragment instanceof SettingsFragment) {
            return;
        }

        if (mPreviousFragment != null) {
            Timber.d("showFragment: destroying previous fragment %s", mPreviousFragment.getClass().getSimpleName());
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            ft.remove(mPreviousFragment);
            mPreviousFragment = null;
        }

        // Remove the current fragment and push it into the backstack.
        if (installed != null) {
            mPreviousFragment = installed;
            ft.detach(mPreviousFragment);
        }

        // Show the new one
        ft.add(R.id.frame_container, fragment, FRAGMENT_TAG);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        ft.commit();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // called by the activity on tablets,
        // as we do not set a onClick listener
        // on the toolbar navigation icon
        // while on a tablet
        if (item.getItemId() == android.R.id.home) {
            onBackPressed();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onBackPressed() {
        // close drawer if it is open
        if (mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mNavigationView)) {
            mDrawerLayout.closeDrawer(mNavigationView);
        } else if (shouldPopFromBackStack()) {
            if (mPopSettingsBackStack) {
                Timber.i("Back: Popping from internal back stack");
                mPopSettingsBackStack = false;
                mFragmentManager.popBackStackImmediate();
                setDrawerAsUp(false);
            } else {
                Timber.i("Back: Popping from custom back stack");
                // Custom back stack
                popFromBackStack();
                ActionBar actionBar = getSupportActionBar();
                if (isTabletLayout && actionBar != null) {
                    actionBar.setDisplayHomeAsUpEnabled(false);
                }
            }
        } else {
            ActivityCompat.finishAfterTransition(this);
            Timber.i("Back: App closed");
        }
    }

    /**
     * @return true if we should pop from our custom back stack.
     */
    private boolean shouldPopFromBackStack() {

        if (mPreviousFragment == null) {
            return false; // Nothing in the back stack
        }
        final Fragment installed = getInstalledFragment();
        if (installed == null) {
            // If no fragment is installed right now, do nothing.
            return false;
        }
        // Okay now we have 2 fragments; the one in the back stack and the one that's currently
        // installed.
        return !(installed instanceof AttendanceListFragment || installed instanceof TimeTablePagerFragment);

    }

    /**
     * Pop from our custom back stack.
     */
    private void popFromBackStack() {
        if (mPreviousFragment == null) {
            return;
        }
        final FragmentTransaction ft = mFragmentManager.beginTransaction();
        final Fragment installed = getInstalledFragment();
        int position = Fragments.ATTENDANCE.getValue();
        Timber.i("backstack: [pop] %s -> %s", installed.getClass().getSimpleName(),
                mPreviousFragment.getClass().getSimpleName());

        ft.remove(installed);
        ft.attach(mPreviousFragment);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
        ft.commit();

        // redraw fragment
        if (mPreviousFragment instanceof AttendanceListFragment) {
            position = Fragments.ATTENDANCE.getValue();
        } else if (mPreviousFragment instanceof TimeTablePagerFragment) {
            position = Fragments.TIMETABLE.getValue();
            //((TimeTablePagerFragment) mPreviousFragment).updateFragmentsData();
            // fixme: this is a crude hack for viewpager not redrawing itself
            showFragment(new TimeTablePagerFragment());
        }
        selectItem(position);
        mPreviousFragment = null;
    }

    @SuppressWarnings("CommitPrefEdits")
    private void persistCurrentFragment() {
        if (!LOGGED_OUT) {
            SharedPreferences.Editor editor = getSharedPreferences("SETTINGS", 0).edit();
            mCurrentSelectedPosition = mCurrentSelectedPosition == Fragments.SETTINGS.getValue()
                    ? Fragments.ATTENDANCE.getValue()
                    : mCurrentSelectedPosition;
            editor.putInt(PREFERENCE_ACTIVATED_FRAGMENT, mCurrentSelectedPosition).commit();
        }
    }

    private int reloadCurrentFragment() {
        SharedPreferences settings = getSharedPreferences("SETTINGS", 0);
        return settings.getInt(PREFERENCE_ACTIVATED_FRAGMENT, Fragments.ATTENDANCE.getValue());
    }

    @Override
    public void setTitle(CharSequence title) {
        mToolbar.setTitle(title);
        mToolbar.setSubtitle("");
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        if (mDrawerToggle != null)
            mDrawerToggle.syncState();

        // Toolbar#setTitle is called by the system on onCreate and
        // again over here which sets the activity label
        // as the title.
        // So we need to call setTitle again as well
        // to show the correct title.
        setTitle(mNavTitles[mCurrentSelectedPosition - 1]);
    }

    /**
     * @return currently installed {@link Fragment} (1-pane has only one at most), or null if none
     *         exists.
     */
    private Fragment getInstalledFragment() {
        return mFragmentManager.findFragmentByTag(FRAGMENT_TAG);
    }

    private boolean isAttendanceListInstalled() {
        return getInstalledFragment() instanceof AttendanceListFragment;
    }

    private boolean isTimeTablePagerInstalled() {
        return getInstalledFragment() instanceof TimeTablePagerFragment;
    }

    private boolean isSettingsInstalled() {
        return getInstalledFragment() instanceof SettingsFragment;
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        // for orientation changes, etc.
        if (mPreviousFragment != null) {
            mFragmentManager.putFragment(outState, PREVIOUS_FRAGMENT_TAG, mPreviousFragment);
            Timber.d("previous fag saved: %s", mPreviousFragment.getClass().getSimpleName());
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (mDrawerToggle != null)
            mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public void onPause() {
        persistCurrentFragment();
        super.onPause();
    }

    @Override
    public void onDestroy() {
        if (mDrawerLayout != null)
            mDrawerLayout.removeDrawerListener(mDrawerToggle);
        mDb.close();
        super.onDestroy();
    }

    /**
     * Reference to fragment positions
     */
    public enum Fragments {
        ATTENDANCE(1), TIMETABLE(2), SETTINGS(3);

        private final int value;

        Fragments(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    }

}