com.evandroid.musica.fragment.LocalLyricsFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.evandroid.musica.fragment.LocalLyricsFragment.java

Source

/*
 * *
 *  * This file is part of QuickLyric
 *  * Created by geecko
 *  *
 *  * QuickLyric 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.
 *  *
 *  * QuickLyric 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 QuickLyric.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package com.evandroid.musica.fragment;

import android.animation.ObjectAnimator;
import android.app.ListFragment;
import android.os.Bundle;
import android.support.v4.view.VelocityTrackerCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.CardView;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;

import com.evandroid.musica.MainLyricActivity;
import com.evandroid.musica.R;
import com.evandroid.musica.adapter.LocalAdapter;
import com.evandroid.musica.lyrics.Lyrics;
import com.evandroid.musica.tasks.DBContentLister;
import com.evandroid.musica.tasks.WriteToDatabaseTask;
import com.evandroid.musica.utils.AnimatorActionListener;
import com.evandroid.musica.view.AnimatedExpandableListView;
import com.evandroid.musica.view.BackgroundContainer;

import java.util.ArrayList;
import java.util.HashMap;

public class LocalLyricsFragment extends ListFragment {

    public static final int REQUEST_CODE = 0;
    public boolean showTransitionAnim = true;
    public boolean isActiveFragment = false;
    public ArrayList<ArrayList<Lyrics>> lyricsArray = null;
    private AnimatedExpandableListView megaListView;
    private ProgressBar progressBar;
    private BackgroundContainer mBackgroundContainer;
    private boolean mSwiping;

    private final View.OnTouchListener mTouchListener = new View.OnTouchListener() {
        float mDownX;
        private int mSwipeSlop = -1;
        private boolean mItemPressed;
        private VelocityTracker mVelocityTracker = null;
        private HashMap<Long, Integer> mItemIdTopMap = new HashMap<>();

        @Override
        public boolean onTouch(final View v, MotionEvent event) {
            int index = event.getActionIndex();
            int pointerId = event.getPointerId(index);

            if (mSwipeSlop < 0) {
                mSwipeSlop = ViewConfiguration.get(getActivity()).getScaledTouchSlop();
            }
            int groupPosition = ((LocalAdapter.ChildViewHolder) v.getTag()).groupPosition;
            int childPosition = 90;

            for (int c = 0; c < megaListView.getChildCount(); c++)
                if (megaListView.getChildAt(c) == v) {
                    childPosition = c;
                    break;
                }

            v.onTouchEvent(event);

            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (mItemPressed) {
                    // Multi-item swipes not handled
                    return false;
                }
                mItemPressed = true;
                mDownX = event.getX();
                if (mVelocityTracker == null) {
                    // Retrieve a new VelocityTracker object to watch the velocity of a motion.
                    mVelocityTracker = VelocityTracker.obtain();
                } else {
                    // Reset the velocity tracker back to its initial state.
                    mVelocityTracker.clear();
                }
                mVelocityTracker.addMovement(event);
                break;
            case MotionEvent.ACTION_CANCEL:
                v.setAlpha(1);
                v.setTranslationX(0);
                if (((LocalAdapter) megaListView.getExpandableListAdapter()).getGroup(groupPosition).size() <= 1) {
                    View groupView = megaListView.getChildAt(childPosition - 1);
                    if (groupView != null && groupView.getTag() instanceof LocalAdapter.GroupViewHolder) {
                        groupView.setTranslationX(0);
                        groupView.setAlpha(1);
                    }
                }
                mItemPressed = false;
                mVelocityTracker.recycle();
                mVelocityTracker = null;
                break;
            case MotionEvent.ACTION_MOVE: {
                mVelocityTracker.addMovement(event);
                float x = event.getX() + v.getTranslationX();
                float deltaX = x - mDownX;
                float deltaXAbs = Math.abs(deltaX);
                if (!mSwiping) {
                    if (deltaXAbs > mSwipeSlop) {
                        mSwiping = true;
                        getListView().requestDisallowInterceptTouchEvent(true);
                        int diff = 0;
                        if (((LocalAdapter) megaListView.getExpandableListAdapter()).getGroup(groupPosition)
                                .size() <= 1) {
                            View groupView = megaListView.getChildAt(childPosition - 1);
                            if (groupView != null)
                                diff = groupView.getHeight();
                        }
                        mBackgroundContainer.showBackground(v.getTop() - diff, v.getHeight() + diff);
                    }
                }
                if (mSwiping) {
                    v.setTranslationX((x - mDownX));
                    v.setAlpha(1 - deltaXAbs / v.getWidth());
                    if (((LocalAdapter) megaListView.getExpandableListAdapter()).getGroup(groupPosition)
                            .size() <= 1) {
                        View groupView = megaListView.getChildAt(childPosition - 1);
                        if (groupView != null && groupView.getTag() instanceof LocalAdapter.GroupViewHolder) {
                            groupView.setTranslationX((x - mDownX));
                            groupView.setAlpha(1 - deltaXAbs / v.getWidth());
                        }
                    }
                }
            }
                break;
            case MotionEvent.ACTION_UP: {
                // User let go - figure out whether to animate the view out, or back into place
                if (mSwiping) {
                    float x = event.getX() + v.getTranslationX();
                    float deltaX = x - mDownX;
                    float deltaXAbs = Math.abs(deltaX);
                    float fractionCovered;
                    float endX;
                    float endAlpha;
                    final boolean remove;
                    mVelocityTracker.computeCurrentVelocity(1000);
                    float velocityX = Math.abs(VelocityTrackerCompat.getXVelocity(mVelocityTracker, pointerId));
                    if (velocityX > 700 || deltaXAbs > v.getWidth() / 4) {
                        fractionCovered = deltaXAbs / v.getWidth();
                        endX = deltaX < 0 ? -v.getWidth() : v.getWidth();
                        endAlpha = 0;
                        remove = true;
                    } else {
                        // Not far enough - animate it back
                        fractionCovered = 1 - (deltaXAbs / v.getWidth());
                        endX = 0;
                        endAlpha = 1;
                        remove = false;
                    }
                    mVelocityTracker.clear();
                    int SWIPE_DURATION = 600;
                    long duration = (int) ((1 - fractionCovered) * SWIPE_DURATION);
                    getListView().setEnabled(false);
                    v.animate().setDuration(Math.abs(duration)).alpha(endAlpha).translationX(endX)
                            .setListener(new AnimatorActionListener(new Runnable() {
                                @Override
                                public void run() {
                                    // Restore animated values
                                    v.setAlpha(1);
                                    v.setTranslationX(0);
                                    if (remove) {
                                        animateRemoval(getListView(), v);
                                    } else {
                                        mBackgroundContainer.hideBackground();
                                        getListView().setEnabled(true);
                                    }
                                }
                            }, AnimatorActionListener.ActionType.END));
                    if (((LocalAdapter) megaListView.getExpandableListAdapter()).getGroup(groupPosition)
                            .size() <= 1) {
                        View groupView = megaListView.getChildAt(childPosition - 1);
                        if (groupView != null && groupView.getTag() instanceof LocalAdapter.GroupViewHolder)
                            groupView.animate().setDuration(Math.abs(duration)).alpha(endAlpha).translationX(endX);
                    }
                }
            }
                mSwiping = false;
                mItemPressed = false;
                break;
            default:
                return false;
            }
            return true;
        }

        private void animateRemoval(final ListView listview, View viewToRemove) {
            int firstVisiblePosition = listview.getFirstVisiblePosition();
            for (int i = 0; i < listview.getChildCount(); ++i) {
                View child = listview.getChildAt(i);
                if (child != viewToRemove) {
                    int position = firstVisiblePosition + i;
                    long itemId = listview.getAdapter().getItemId(position);
                    mItemIdTopMap.put(itemId, child.getTop());
                }
            }
            mBackgroundContainer.hideBackground();
            final boolean[] firstAnimation = { true };
            // Delete the item from the adapter
            LocalAdapter.ChildViewHolder childViewHolder = (LocalAdapter.ChildViewHolder) viewToRemove.getTag();
            new WriteToDatabaseTask(LocalLyricsFragment.this).execute(LocalLyricsFragment.this, null,
                    childViewHolder.lyrics);
            ((LocalAdapter) getExpandableListAdapter()).remove(childViewHolder.groupPosition, viewToRemove);

            final ViewTreeObserver[] observer = { listview.getViewTreeObserver() };
            observer[0].addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                public boolean onPreDraw() {
                    observer[0].removeOnPreDrawListener(this);
                    firstAnimation[0] = true;
                    int firstVisiblePosition = listview.getFirstVisiblePosition();
                    for (int i = 0; i < listview.getChildCount(); ++i) {
                        final View child = listview.getChildAt(i);
                        int position = firstVisiblePosition + i;
                        long itemId = getListView().getAdapter().getItemId(position);
                        Integer formerTop = mItemIdTopMap.get(itemId);
                        int newTop = child.getTop();
                        if (formerTop != null) {
                            if (formerTop != newTop) {
                                int delta = formerTop - newTop;
                                child.setTranslationY(delta);
                                int MOVE_DURATION = 500;
                                child.animate().setDuration(MOVE_DURATION).translationY(0);
                                if (firstAnimation[0]) {
                                    child.animate().setListener(new AnimatorActionListener(new Runnable() {
                                        public void run() {
                                            mSwiping = false;
                                            getListView().setEnabled(true);
                                        }
                                    }, AnimatorActionListener.ActionType.END));
                                    firstAnimation[0] = false;
                                }
                            }
                        } else {
                            // Animate new views along with the others. The catch is that they did not
                            // exist in the start state, so we must calculate their starting position
                            // based on neighboring views.
                            int childHeight = child.getHeight() + listview.getDividerHeight();
                            formerTop = newTop + (i > 0 ? childHeight : -childHeight);
                            int delta = formerTop - newTop;
                            child.setTranslationY(delta);
                            int MOVE_DURATION = 500;
                            child.animate().setDuration(MOVE_DURATION).translationY(0);
                            if (firstAnimation[0]) {
                                child.animate().setListener(new AnimatorActionListener(new Runnable() {
                                    public void run() {
                                        mSwiping = false;
                                        getListView().setEnabled(true);
                                    }
                                }, AnimatorActionListener.ActionType.END));
                                firstAnimation[0] = false;
                            }
                        }
                    }
                    if (firstAnimation[0]) {
                        mSwiping = false;
                        getListView().setEnabled(true);
                        firstAnimation[0] = false;
                    }
                    mItemIdTopMap.clear();
                    return true;
                }
            });
        }
    };

    public void animateUndo(Lyrics[] lyricsArray) {
        final HashMap<Long, Integer> itemIdTopMap = new HashMap<>();
        int firstVisiblePosition = megaListView.getFirstVisiblePosition();
        for (int i = 0; i < megaListView.getChildCount(); ++i) {
            View child = megaListView.getChildAt(i);
            int position = firstVisiblePosition + i;
            long itemId = megaListView.getAdapter().getItemId(position);
            itemIdTopMap.put(itemId, child.getTop());
        }
        final boolean[] firstAnimation = { true };
        // Delete the item from the adapter
        final int groupPosition = ((LocalAdapter) getExpandableListAdapter()).add(lyricsArray[0]);
        megaListView.setAdapter(getExpandableListAdapter());
        megaListView.post(new Runnable() {
            @Override
            public void run() {
                megaListView.expandGroupWithAnimation(groupPosition);
            }
        });
        new WriteToDatabaseTask(LocalLyricsFragment.this).execute(LocalLyricsFragment.this, null, lyricsArray);

        final ViewTreeObserver[] observer = { megaListView.getViewTreeObserver() };
        observer[0].addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            public boolean onPreDraw() {
                observer[0].removeOnPreDrawListener(this);
                firstAnimation[0] = true;
                int firstVisiblePosition = megaListView.getFirstVisiblePosition();
                for (int i = 0; i < megaListView.getChildCount(); ++i) {
                    final View child = megaListView.getChildAt(i);
                    int position = firstVisiblePosition + i;
                    long itemId = getListView().getAdapter().getItemId(position);
                    Integer formerTop = itemIdTopMap.get(itemId);
                    int newTop = child.getTop();
                    if (formerTop != null) {
                        if (formerTop != newTop) {
                            int delta = formerTop - newTop;
                            child.setTranslationY(delta);
                            int MOVE_DURATION = 500;
                            child.animate().setDuration(MOVE_DURATION).translationY(0);
                            if (firstAnimation[0]) {
                                child.animate().setListener(new AnimatorActionListener(new Runnable() {
                                    public void run() {
                                        mBackgroundContainer.hideBackground();
                                        mSwiping = false;
                                        getListView().setEnabled(true);
                                    }
                                }, AnimatorActionListener.ActionType.END));
                                firstAnimation[0] = false;
                            }
                        }
                    } else {
                        // Animate new views along with the others. The catch is that they did not
                        // exist in the start state, so we must calculate their starting position
                        // based on neighboring views.
                        int childHeight = child.getHeight() + megaListView.getDividerHeight();
                        formerTop = newTop - childHeight;
                        int delta = formerTop - newTop;
                        final float z = ((CardView) child).getCardElevation();
                        ((CardView) child).setCardElevation(0f);
                        child.setTranslationY(delta);
                        final int MOVE_DURATION = 500;
                        child.animate().setDuration(MOVE_DURATION).translationY(0);
                        child.animate().setListener(new AnimatorActionListener(new Runnable() {
                            public void run() {
                                mBackgroundContainer.hideBackground();
                                mSwiping = false;
                                getListView().setEnabled(true);
                                ObjectAnimator anim = ObjectAnimator.ofFloat(child, "cardElevation", 0f, z);
                                anim.setDuration(200);
                                anim.setInterpolator(new AccelerateInterpolator());
                                anim.start();
                            }
                        }, AnimatorActionListener.ActionType.END));
                        firstAnimation[0] = false;
                    }
                }
                if (firstAnimation[0]) {
                    mBackgroundContainer.hideBackground();
                    mSwiping = false;
                    getListView().setEnabled(true);
                    firstAnimation[0] = false;
                }
                itemIdTopMap.clear();
                return true;
            }
        });
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        setRetainInstance(true);
        setHasOptionsMenu(true);
        View layout = inflater.inflate(R.layout.local_listview, container, false);
        megaListView = (AnimatedExpandableListView) layout.findViewById(android.R.id.list);
        mBackgroundContainer = (BackgroundContainer) layout.findViewById(R.id.listViewBackground);
        progressBar = (ProgressBar) layout.findViewById(R.id.list_progress);
        return layout;
    }

    @Override
    public void onActivityCreated(Bundle onSavedInstanceState) {
        super.onActivityCreated(onSavedInstanceState);
        if (megaListView != null) {
            View fragmentView = getView();
            TypedValue typedValue = new TypedValue();
            getActivity().getTheme().resolveAttribute(android.R.attr.colorBackground, typedValue, true);
            if (fragmentView != null)
                fragmentView.setBackgroundColor(typedValue.data);
            megaListView.setDividerHeight(0);
            megaListView.setFastScrollEnabled(true);
            megaListView.setDrawSelectorOnTop(true);
        }
    }

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

        megaListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {

            @Override
            public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
                final ImageView indicator = (ImageView) v.findViewById(R.id.group_indicator);
                RotateAnimation anim;
                if (megaListView.isGroupExpanded(groupPosition)) {
                    megaListView.collapseGroupWithAnimation(groupPosition);
                    if (indicator != null) {
                        anim = new RotateAnimation(180f, 360f, indicator.getWidth() / 2, indicator.getHeight() / 2);
                        anim.setInterpolator(new DecelerateInterpolator(3));
                        anim.setDuration(500);
                        anim.setFillAfter(true);
                        indicator.startAnimation(anim);
                    }
                } else {
                    megaListView.expandGroupWithAnimation(groupPosition);
                    if (indicator != null) {
                        anim = new RotateAnimation(0f, 180f, indicator.getWidth() / 2, indicator.getHeight() / 2);
                        anim.setInterpolator(new DecelerateInterpolator(2));
                        anim.setDuration(500);
                        anim.setFillAfter(true);
                        indicator.startAnimation(anim);
                    }
                }
                return true;
            }
        });

        megaListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition,
                    long id) {
                if (mSwiping) {
                    mSwiping = false;
                    return false;
                }
                final MainLyricActivity mainLyricActivity = (MainLyricActivity) getActivity();
                megaListView.setOnChildClickListener(null); // prevents bug on double tap
                mainLyricActivity.updateLyricsFragment(R.animator.slide_out_start, R.animator.slide_in_start, true,
                        lyricsArray.get(groupPosition).get(childPosition));
                return true;
            }
        });

        this.isActiveFragment = true;
        new DBContentLister(this).execute();
    }

    public void update(final ArrayList<ArrayList<Lyrics>> results) {
        if (getView() == null)
            return;
        int index = megaListView.getFirstVisiblePosition();
        View v = megaListView.getChildAt(0);
        int top = (v == null) ? 0 : (v.getTop() - megaListView.getPaddingTop());
        lyricsArray = results;

        megaListView.setAdapter(new LocalAdapter(getActivity(), results, mTouchListener, megaListView));
        megaListView
                .setEmptyView(((ViewGroup) getView().findViewById(R.id.local_empty_database_textview).getParent()));
        getListView().setSelectionFromTop(index, top);
        setListShown(true);
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        if (!hidden)
            this.onViewCreated(getView(), null);
        else
            this.isActiveFragment = false;
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        MainLyricActivity mainLyricActivity = (MainLyricActivity) this.getActivity();
        ActionBar actionBar = (mainLyricActivity).getSupportActionBar();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.action_scan:
        }
        return false;
    }

    public void setListShown(final boolean visible) {
        final Animation fadeIn = AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in);
        final Animation fadeOut = AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out);
        Animation.AnimationListener listener = new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                progressBar.setVisibility(visible ? View.GONE : View.VISIBLE);
                megaListView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        };
        fadeIn.setAnimationListener(listener);
        fadeOut.setAnimationListener(listener);
        progressBar.startAnimation(visible ? fadeOut : fadeIn);
        megaListView.startAnimation(visible ? fadeIn : fadeOut);
    }

    public ExpandableListAdapter getExpandableListAdapter() {
        return megaListView.getExpandableListAdapter();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}