com.shalzz.attendance.fragment.AttendanceListFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.shalzz.attendance.fragment.AttendanceListFragment.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.fragment;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.text.TextUtils;
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.view.ViewTreeObserver;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.bugsnag.android.Bugsnag;
import com.github.amlcurran.showcaseview.ShowcaseView;
import com.github.amlcurran.showcaseview.targets.ViewTarget;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
import com.shalzz.attendance.CircularIndeterminate;
import com.shalzz.attendance.DividerItemDecoration;
import com.shalzz.attendance.Miscellaneous;
import com.shalzz.attendance.R;
import com.shalzz.attendance.adapter.ExpandableListAdapter;
import com.shalzz.attendance.controllers.AttendanceController;
import com.shalzz.attendance.controllers.UserAccount;
import com.shalzz.attendance.network.DataAPI;
import com.shalzz.attendance.wrapper.MultiSwipeRefreshLayout;
import com.shalzz.attendance.wrapper.MyApplication;

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

import butterknife.BindBool;
import butterknife.BindDimen;
import butterknife.BindString;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;

public class AttendanceListFragment extends Fragment implements ExpandableListAdapter.SubjectItemExpandedListener {

    /**
     * The {@link android.support.v4.widget.SwipeRefreshLayout} that detects swipe gestures and
     * triggers callbacks in the app.
     */
    @BindView(R.id.swipe_refresh_atten)
    public MultiSwipeRefreshLayout mSwipeRefreshLayout;

    @BindView(R.id.circular_indet_atten)
    public CircularIndeterminate mProgress;

    @BindView(R.id.atten_recycler_view)
    public RecyclerView mRecyclerView;

    @BindView(R.id.empty_view)
    public View emptyView;

    public static class EmptyView {
        @BindView(R.id.emptyStateImageView)
        public ImageView ImageView;

        @BindView(R.id.emptyStateTitleTextView)
        public TextView TitleTextView;

        @BindView(R.id.emptyStateContentTextView)
        public TextView ContentTextView;

        @BindView(R.id.emptyStateButton)
        public Button Button;
    }

    @BindBool(R.bool.use_grid_layout)
    boolean useGridLayout;

    @BindDimen(R.dimen.atten_view_expanded_elevation)
    float mExpandedItemTranslationZ;

    @BindString(R.string.hint_search)
    String hint_search_view;

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

    @Inject
    DataAPI api;

    UserAccount userAccount;

    @Nullable
    private LinearLayoutManager mLinearLayoutManager;

    @Nullable
    private StaggeredGridLayoutManager mGridLayoutManager;

    private Context mContext;
    private String mTag = "Attendance List Fragment";
    private AttendanceController controller;

    private final int GRID_LAYOUT_SPAN_COUNT = 2;
    private final int mFadeInDuration = 150;
    private final int mFadeInStartDelay = 150;
    private final int mFadeOutDuration = 20;
    private final int mExpandCollapseDuration = 200;
    private Unbinder unbinder;
    public EmptyView mEmptyView = new EmptyView();

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

        mTracker.setScreenName(getClass().getSimpleName());
        mTracker.send(new HitBuilders.ScreenViewBuilder().build());
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (container == null)
            return null;
        Bugsnag.setContext("AttendanceList");
        MyApplication.getAppComponent().inject(this);

        mContext = getActivity();
        userAccount = new UserAccount(mContext, api);
        setHasOptionsMenu(true);
        View mView = inflater.inflate(R.layout.fragment_attendance, container, false);
        unbinder = ButterKnife.bind(this, mView);
        ButterKnife.bind(mEmptyView, emptyView);

        mSwipeRefreshLayout.setSwipeableChildren(R.id.atten_recycler_view);

        // Set the color scheme of the SwipeRefreshLayout by providing 4 color resource ids
        mSwipeRefreshLayout.setColorSchemeResources(R.color.swipe_color_1, R.color.swipe_color_2,
                R.color.swipe_color_3, R.color.swipe_color_4);

        if (useGridLayout) {
            mGridLayoutManager = new StaggeredGridLayoutManager(GRID_LAYOUT_SPAN_COUNT,
                    StaggeredGridLayoutManager.VERTICAL);
            mGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
        } else {
            mLinearLayoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false);
            mLinearLayoutManager.setSmoothScrollbarEnabled(false);
            mLinearLayoutManager.setStackFromEnd(false);
            mLinearLayoutManager.setAutoMeasureEnabled(true);
        }

        mRecyclerView.setLayoutManager(useGridLayout ? mGridLayoutManager : mLinearLayoutManager);

        RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(mContext,
                DividerItemDecoration.VERTICAL_LIST);
        mRecyclerView.addItemDecoration(itemDecoration);

        return mView;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        controller = new AttendanceController(mContext, this, api);
        mProgress.setVisibility(View.VISIBLE);

        mSwipeRefreshLayout.setOnRefreshListener(() -> controller.updateSubjects());

    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getLoaderManager().initLoader(0, null, controller);
    }

    public void showcaseView() {
        if (mRecyclerView != null && mRecyclerView.getChildAt(2) != null) {
            ViewTarget target = new ViewTarget(mRecyclerView.getChildAt(2));

            new ShowcaseView.Builder(getActivity()).setStyle(R.style.ShowcaseTheme).setTarget(target)
                    .singleShot(2222).setContentTitle(getString(R.string.sv_attendance_title))
                    .setContentText(getString(R.string.sv_attendance_content)).build();
        }
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
        // Inflate the menu; this adds items to the action bar if it is present.
        menuInflater.inflate(R.menu.main, menu);
        MenuItem searchItem = menu.findItem(R.id.menu_search);

        final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
        searchView.setQueryHint(hint_search_view);
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {

            @Override
            public boolean onQueryTextSubmit(String arg0) {
                Miscellaneous.closeKeyboard(mContext, searchView);
                return false;
            }

            @Override
            public boolean onQueryTextChange(String arg0) {
                String filter = !TextUtils.isEmpty(arg0) ? arg0 : null;
                Bundle bundle = new Bundle();
                bundle.putString(AttendanceController.SUBJECT_FILTER, filter);
                // destroy the loader first to clear the adapter
                getLoaderManager().destroyLoader(0);
                getLoaderManager().restartLoader(0, bundle, controller);
                return false;
            }
        });
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.menu_logout) {
            userAccount.Logout();
            return true;
        } else if (item.getItemId() == R.id.menu_refresh) {
            // We make sure that the SwipeRefreshLayout is displaying it's refreshing indicator
            if (!mSwipeRefreshLayout.isRefreshing()) {
                mSwipeRefreshLayout.setRefreshing(true);
                controller.updateSubjects();
            }
            return true;
        } else if (item.getItemId() == R.id.menu_search) {
            mTracker.send(new HitBuilders.EventBuilder().setCategory("Action").setAction("Search").build());
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onItemExpanded(final View view) {
        final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        final ExpandableListAdapter.GenericViewHolder viewHolder = (ExpandableListAdapter.GenericViewHolder) view
                .getTag();
        final RelativeLayout childView = viewHolder.childView;
        childView.measure(spec, spec);
        final int startingHeight = view.getHeight();
        final ViewTreeObserver observer = mRecyclerView.getViewTreeObserver();
        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                // We don'mTracker want to continue getting called for every draw.
                if (observer.isAlive()) {
                    observer.removeOnPreDrawListener(this);
                }
                // Calculate some values to help with the animation.
                final int endingHeight = view.getHeight();
                final int distance = Math.abs(endingHeight - startingHeight);
                final int baseHeight = Math.min(endingHeight, startingHeight);
                final boolean isExpanded = endingHeight > startingHeight;

                // Set the views back to the start state of the animation
                view.getLayoutParams().height = startingHeight;
                if (!isExpanded) {
                    viewHolder.childView.setVisibility(View.VISIBLE);
                }

                // Set up the fade effect for the action buttons.
                if (isExpanded) {
                    // Start the fade in after the expansion has partly completed, otherwise it
                    // will be mostly over before the expansion completes.
                    viewHolder.childView.setAlpha(0f);
                    viewHolder.childView.animate().alpha(1f).setStartDelay(mFadeInStartDelay)
                            .setDuration(mFadeInDuration).start();
                } else {
                    viewHolder.childView.setAlpha(1f);
                    viewHolder.childView.animate().alpha(0f).setDuration(mFadeOutDuration).start();
                }
                view.requestLayout();

                // Set up the animator to animate the expansion and shadow depth.
                ValueAnimator animator = isExpanded ? ValueAnimator.ofFloat(0f, 1f) : ValueAnimator.ofFloat(1f, 0f);

                // scroll to make the view fully visible.
                mRecyclerView.smoothScrollToPosition(viewHolder.position);

                animator.addUpdateListener(animator1 -> {
                    Float value = (Float) animator1.getAnimatedValue();

                    // For each value from 0 to 1, animate the various parts of the layout.
                    view.getLayoutParams().height = (int) (value * distance + baseHeight);
                    float z = mExpandedItemTranslationZ * value;
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        view.setTranslationZ(z);
                    }
                    view.requestLayout();
                });

                // Set everything to their final values when the animation's done.
                animator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        view.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;

                        if (!isExpanded) {
                            viewHolder.childView.setVisibility(View.GONE);
                        } else {
                            // This seems like it should be unnecessary, but without this, after
                            // navigating out of the activity and then back, the action view alpha
                            // is defaulting to the value (0) at the start of the expand animation.
                            viewHolder.childView.setAlpha(1);
                        }
                    }
                });

                animator.setDuration(mExpandCollapseDuration);
                animator.start();

                // Return false so this draw does not occur to prevent the final frame from
                // being drawn for the single frame before the animations start.
                return false;
            }
        });
    }

    @Override
    public View getViewForCallId(long callId) {
        if (!useGridLayout) {
            assert mLinearLayoutManager != null;
            int firstPosition = mLinearLayoutManager.findFirstVisibleItemPosition();
            int lastPosition = mLinearLayoutManager.findLastVisibleItemPosition();

            for (int position = 0; position <= lastPosition - firstPosition; position++) {
                View view = mRecyclerView.getChildAt(position);

                if (view != null) {
                    final ExpandableListAdapter.GenericViewHolder viewHolder = (ExpandableListAdapter.GenericViewHolder) view
                            .getTag();
                    if (viewHolder != null && viewHolder.position == callId) {
                        return view;
                    }
                }
            }
        } else {
            int firstPosition[] = { 0, 0 };
            int lastPosition[] = { 0, 0 };
            assert mGridLayoutManager != null;
            mGridLayoutManager.findFirstVisibleItemPositions(firstPosition);
            mGridLayoutManager.findLastVisibleItemPositions(lastPosition);

            for (int i = 0; i < GRID_LAYOUT_SPAN_COUNT; i++) {
                for (int position = 0; position <= lastPosition[i] - firstPosition[i]; position++) {
                    View view = mRecyclerView.getChildAt(position);

                    if (view != null) {
                        final ExpandableListAdapter.GenericViewHolder viewHolder = (ExpandableListAdapter.GenericViewHolder) view
                                .getTag();
                        if (viewHolder != null && viewHolder.position == callId) {
                            return view;
                        }
                    }
                }
            }
        }
        return null;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
        controller.destroyAds();
    }
}