org.gateshipone.odyssey.fragments.MyMusicFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.gateshipone.odyssey.fragments.MyMusicFragment.java

Source

/*
 * Copyright (C) 2016  Hendrik Borghorst & Frederik Luetkes
 *
 * 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 org.gateshipone.odyssey.fragments;

import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.RemoteException;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.SearchView;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;

import org.gateshipone.odyssey.R;
import org.gateshipone.odyssey.listener.ToolbarAndFABCallback;
import org.gateshipone.odyssey.playbackservice.PlaybackServiceConnection;
import org.gateshipone.odyssey.utils.ThemeUtils;

public class MyMusicFragment extends Fragment implements TabLayout.OnTabSelectedListener {

    /**
     * Callback to setup toolbar and fab
     */
    protected ToolbarAndFABCallback mToolbarAndFABCallback;

    /**
     * ServiceConnection object to communicate with the PlaybackService
     */
    private PlaybackServiceConnection mServiceConnection;

    /**
     * Save the viewpager for later usage
     */
    private ViewPager mMyMusicViewPager;

    /**
     * Save the pageradapter for later usage
     */
    private MyMusicPagerAdapter mMyMusicPagerAdapter;

    /**
     * Save the searchview for later usage
     */
    private SearchView mSearchView;

    /**
     * Save the optionsmenu for later usage
     */
    private Menu mOptionMenu;

    /**
     * Saved search string when user rotates devices
     */
    private String mSearchString;

    /**
     * Constant for state saving
     */
    public final static String MYMUSICFRAGMENT_SAVED_INSTANCE_SEARCH_STRING = "MyMusicFragment.SearchString";

    /**
     * key value for arguments of the fragment
     */
    public final static String MY_MUSIC_REQUESTED_TAB = "ARG_REQUESTED_TAB";

    /**
     * enum for the default tab
     */
    public enum DEFAULTTAB {
        ARTISTS, ALBUMS, TRACKS
    }

    /**
     * Called to create instantiate the UI of the fragment.
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_my_music, container, false);

        // create tabs
        TabLayout tabLayout = (TabLayout) rootView.findViewById(R.id.my_music_tab_layout);

        // setup icons for tabs
        final ColorStateList tabColors = tabLayout.getTabTextColors();
        Resources res = getResources();
        Drawable drawable = res.getDrawable(R.drawable.ic_recent_actors_24dp, null);
        if (drawable != null) {
            Drawable icon = DrawableCompat.wrap(drawable);
            DrawableCompat.setTintList(icon, tabColors);
            tabLayout.addTab(tabLayout.newTab().setIcon(icon));
        }
        drawable = res.getDrawable(R.drawable.ic_album_24dp, null);
        if (drawable != null) {
            Drawable icon = DrawableCompat.wrap(drawable);
            DrawableCompat.setTintList(icon, tabColors);
            tabLayout.addTab(tabLayout.newTab().setIcon(icon));
        }
        drawable = res.getDrawable(R.drawable.ic_my_library_music_24dp, null);
        if (drawable != null) {
            Drawable icon = DrawableCompat.wrap(drawable);
            DrawableCompat.setTintList(icon, tabColors);
            tabLayout.addTab(tabLayout.newTab().setIcon(icon));
        }
        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);

        // setup viewpager
        mMyMusicViewPager = (ViewPager) rootView.findViewById(R.id.my_music_viewpager);
        mMyMusicPagerAdapter = new MyMusicPagerAdapter(getChildFragmentManager());
        mMyMusicViewPager.setAdapter(mMyMusicPagerAdapter);
        mMyMusicViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
        mMyMusicViewPager.setOffscreenPageLimit(2);
        tabLayout.addOnTabSelectedListener(this);

        // set start page
        Bundle args = getArguments();

        // only set requested tab if no state was saved
        if (args != null && savedInstanceState == null) {
            DEFAULTTAB tab = DEFAULTTAB.values()[args.getInt(MY_MUSIC_REQUESTED_TAB)];

            switch (tab) {
            case ARTISTS:
                mMyMusicViewPager.setCurrentItem(0, false);
                break;
            case ALBUMS:
                mMyMusicViewPager.setCurrentItem(1, false);
                break;
            case TRACKS:
                mMyMusicViewPager.setCurrentItem(2, false);
                break;
            }

        }

        // activate options menu in toolbar
        setHasOptionsMenu(true);

        // set up pbs connection
        mServiceConnection = new PlaybackServiceConnection(getActivity().getApplicationContext());
        mServiceConnection.openConnection();

        // try to resume the saved search string
        if (savedInstanceState != null) {
            mSearchString = savedInstanceState.getString(MYMUSICFRAGMENT_SAVED_INSTANCE_SEARCH_STRING);
        }

        return rootView;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        // save the already typed search string (or null if nothing is entered)
        outState.putString(MYMUSICFRAGMENT_SAVED_INSTANCE_SEARCH_STRING, mSearchString);
    }

    /**
     * Called when the fragment is first attached to its context.
     */
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mToolbarAndFABCallback = (ToolbarAndFABCallback) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString() + " must implement ToolbarAndFABCallback");
        }
    }

    /**
     * Setup toolbar and button callback in last creation state.
     */
    @Override
    public void onResume() {
        super.onResume();

        if (mToolbarAndFABCallback != null) {
            // set up play button
            mToolbarAndFABCallback.setupFAB(getPlayButtonListener(mMyMusicViewPager.getCurrentItem()));
            // set toolbar behaviour and title
            mToolbarAndFABCallback.setupToolbar(getString(R.string.fragment_title_my_music), true, true, false);
        }
    }

    /**
     * Create a ClickListener for the play button if needed.
     */
    private View.OnClickListener getPlayButtonListener(int tab) {
        switch (tab) {
        case 0:
        case 1:
            return null;
        case 2:
            return new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // play all tracks on device
                    try {
                        mServiceConnection.getPBS().playAllTracks();
                    } catch (RemoteException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            };
        default:
            return null;
        }
    }

    /**
     * Called when a tab enters the selected state.
     */
    @Override
    public void onTabSelected(TabLayout.Tab tab) {

        // set viewpager to current page
        mMyMusicViewPager.setCurrentItem(tab.getPosition());

        if (mToolbarAndFABCallback != null) {
            // show fab only for AllTracksFragment
            View.OnClickListener listener = getPlayButtonListener(tab.getPosition());

            // set up play button
            mToolbarAndFABCallback.setupFAB(listener);
        }

        OdysseyFragment fragment = mMyMusicPagerAdapter.getRegisteredFragment(tab.getPosition());
        if (fragment != null) {
            fragment.getContent();

            // Disable memory trimming to prevent removing the shown data
            fragment.enableMemoryTrimming(false);
        }
    }

    /**
     * Called when a tab leaves the selected state.
     * <p/>
     * This method will take care of dismissing the searchview and showing the fab.
     */
    @Override
    public void onTabUnselected(TabLayout.Tab tab) {
        OdysseyFragment fragment = mMyMusicPagerAdapter.getRegisteredFragment(tab.getPosition());

        // dismiss searchview
        if (mSearchView != null && mOptionMenu != null && !mSearchView.isIconified()) {
            if (mSearchView.getQuery().length() > 0) {
                // clear filter only if searchview contains text
                if (fragment != null) {
                    fragment.removeFilter();
                }
            }

            mSearchView.setIconified(true);
            mOptionMenu.findItem(R.id.action_search).collapseActionView();
        }

        if (null != fragment) {
            // Reenable memory trimming now, because the Fragment is hidden
            fragment.enableMemoryTrimming(true);
        }
    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {

    }

    /**
     * Method to reload the fragments.
     */
    public void refresh() {
        // reload tabs
        mMyMusicPagerAdapter.notifyDataSetChanged();
    }

    /**
     * Initialize the options menu.
     * Be sure to call {@link #setHasOptionsMenu} before.
     *
     * @param menu         The container for the custom options menu.
     * @param menuInflater The inflater to instantiate the layout.
     */
    @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.options_menu_my_music, menu);

        mOptionMenu = menu;

        // get tint color
        int tintColor = ThemeUtils.getThemeColor(getContext(), R.attr.odyssey_color_text_accent);

        Drawable drawable = menu.findItem(R.id.action_search).getIcon();
        drawable = DrawableCompat.wrap(drawable);
        DrawableCompat.setTint(drawable, tintColor);
        mOptionMenu.findItem(R.id.action_search).setIcon(drawable);

        mSearchView = (SearchView) menu.findItem(R.id.action_search).getActionView();

        // Check if a search string is saved from before
        if (mSearchString != null) {
            // Expand the view
            mSearchView.setIconified(false);
            menu.findItem(R.id.action_search).expandActionView();
            // Set the query string
            mSearchView.setQuery(mSearchString, false);

            OdysseyFragment fragment = mMyMusicPagerAdapter
                    .getRegisteredFragment(mMyMusicViewPager.getCurrentItem());
            // Notify the adapter
            fragment.applyFilter(mSearchString);
        }

        mSearchView.setOnQueryTextListener(new SearchTextObserver());

        super.onCreateOptionsMenu(menu, menuInflater);
    }

    /**
     * Custom pager adapter to retrieve already registered fragments.
     */
    private class MyMusicPagerAdapter extends FragmentStatePagerAdapter {
        static final int NUMBER_OF_PAGES = 3;

        private SparseArray<OdysseyFragment> mRegisteredFragments;

        public MyMusicPagerAdapter(FragmentManager fm) {
            super(fm);
            mRegisteredFragments = new SparseArray<>();
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            OdysseyFragment fragment = (OdysseyFragment) super.instantiateItem(container, position);
            mRegisteredFragments.put(position, fragment);
            return fragment;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            mRegisteredFragments.remove(position);
            super.destroyItem(container, position, object);
        }

        @Override
        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }

        @Override
        public Fragment getItem(int i) {
            switch (i) {
            case 0:
                return new ArtistsFragment();
            case 1:
                return new AlbumsFragment();
            case 2:
                return new AllTracksFragment();
            default:
                return null;
            }
        }

        @Override
        public int getCount() {
            // this is done in order to reload all tabs
            return NUMBER_OF_PAGES;
        }

        public OdysseyFragment getRegisteredFragment(int position) {
            return mRegisteredFragments.get(position);
        }
    }

    /**
     * Observer class to apply a filter to the current fragment in the viewpager.
     */
    private class SearchTextObserver implements SearchView.OnQueryTextListener {

        @Override
        public boolean onQueryTextSubmit(String query) {
            applyFilter(query);

            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            applyFilter(newText);

            return true;
        }

        private void applyFilter(String filter) {
            OdysseyFragment fragment = mMyMusicPagerAdapter
                    .getRegisteredFragment(mMyMusicViewPager.getCurrentItem());

            if (filter.isEmpty()) {
                mSearchString = null;
                fragment.removeFilter();
            } else {
                mSearchString = filter;
                fragment.applyFilter(filter);
            }
        }
    }
}