com.andrew.apollo.ui.fragments.profile.ApolloFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.andrew.apollo.ui.fragments.profile.ApolloFragment.java

Source

/*
 * Created by Angel Leon (@gubatron), Alden Torres (aldenml)
 * Copyright (c) 2011-2016, FrostWire(R). All rights reserved.
 *
 * 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.andrew.apollo.ui.fragments.profile;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.view.*;
import android.widget.*;
import com.andrew.apollo.MusicStateListener;
import com.andrew.apollo.adapters.ApolloFragmentAdapter;
import com.andrew.apollo.loaders.PlaylistLoader;
import com.andrew.apollo.menu.CreateNewPlaylist;
import com.andrew.apollo.menu.DeleteDialog;
import com.andrew.apollo.menu.FragmentMenuItems;
import com.andrew.apollo.model.*;
import com.andrew.apollo.provider.FavoritesStore;
import com.andrew.apollo.provider.RecentStore;
import com.andrew.apollo.recycler.RecycleHolder;
import com.andrew.apollo.ui.activities.BaseActivity;
import com.andrew.apollo.utils.ApolloUtils;
import com.andrew.apollo.utils.MusicUtils;
import com.andrew.apollo.utils.NavUtils;
import com.andrew.apollo.utils.PreferenceUtils;
import com.andrew.apollo.widgets.ProfileTabCarousel;
import com.andrew.apollo.widgets.VerticalScrollListener;
import com.devspark.appmsg.AppMsg;
import com.frostwire.android.R;
import com.frostwire.logging.Logger;
import com.viewpagerindicator.TitlePageIndicator;

import java.util.List;

/**
 * Created by gubatron on 1/26/16 on a plane.
 *
 * @author gubatron
 * @author aldenml
 */
public abstract class ApolloFragment<T extends ApolloFragmentAdapter<I>, I> extends Fragment
        implements LoaderManager.LoaderCallbacks<List<I>>, AdapterView.OnItemClickListener, MusicStateListener {

    @SuppressWarnings("unused")
    private static Logger LOGGER = Logger.getLogger(ApolloFragment.class);

    private final int GROUP_ID;
    /**
     * LoaderCallbacks identifier
     */
    private final int LOADER_ID;
    /**
     * The list view
     */
    protected ListView mListView;

    /**
     * The grid view
     */
    protected GridView mGridView;

    /**
     * The adapter for the list
     */
    protected T mAdapter;
    /**
     * Represents a song/album/
     */
    protected I mItem;

    /**
     * Song list. The playlist's, the album's, the artist's discography available.
     */
    private long[] mSongList;

    /**
     * Id of a context menu item
     */
    private long mSelectedId;

    /**
     * The Id of the playlist the song belongs to
     */
    long mPlaylistId;

    /**
     * Song, album, and artist name used in the context menu
     */
    private String mSongName, mAlbumName, mArtistName;

    /**
     * Profile header
     */
    ProfileTabCarousel mProfileTabCarousel;

    protected ViewGroup mRootView;

    private volatile long lastRestartLoader;

    protected abstract T createAdapter();

    protected abstract String getLayoutTypeName();

    public abstract void onItemClick(final AdapterView<?> parent, final View view, final int position,
            final long id);

    protected ApolloFragment(int groupId, int loaderId) {
        this.GROUP_ID = groupId;
        this.LOADER_ID = loaderId;
    }

    @SuppressWarnings("deprecation")
    @Override
    public void onAttach(final Activity activity) {
        super.onAttach(activity);
        mProfileTabCarousel = (ProfileTabCarousel) activity.findViewById(R.id.activity_profile_base_tab_carousel);

        if (activity instanceof BaseActivity) {
            // Register the music status listener
            ((BaseActivity) activity).setMusicStateListenerListener(this);
        }
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
            final Bundle savedInstanceState) {
        // The View for the fragment's UI
        if (isSimpleLayout()) {
            mRootView = (ViewGroup) inflater.inflate(R.layout.list_base, null);
            initListView();
        } else {
            // this inflate here is crashing.
            mRootView = (ViewGroup) inflater.inflate(R.layout.grid_base, null);
            initGridView();
        }

        return mRootView;
    }

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Create the adapter
        mAdapter = createAdapter();
    }

    public T getAdapter() {
        return mAdapter;
    }

    @Override
    public void onCreateContextMenu(final ContextMenu menu, final View v,
            final ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);

        // Get the position of the selected item
        final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
        int mSelectedPosition = info.position - mAdapter.getOffset();

        // Create a new song
        mItem = mAdapter.getItem(mSelectedPosition);

        // TODO: Remove these mutable properties, parametrize the onMenuEvent handlers.
        if (mItem instanceof Song) {
            Song mSong = (Song) mItem;
            mSelectedId = mSong.mSongId;
            mSongName = mSong.mSongName;
            mAlbumName = mSong.mAlbumName;
            mArtistName = mSong.mArtistName;
            mSongList = null;
        } else if (mItem instanceof Album) {
            Album mAlbum = (Album) mItem;
            mSelectedId = mAlbum.mAlbumId;
            mSongName = null;
            mAlbumName = mAlbum.mAlbumName;
            mArtistName = mAlbum.mArtistName;
            mSongList = MusicUtils.getSongListForAlbum(getActivity(), mAlbum.mAlbumId);
        } else if (mItem instanceof Artist) {
            Artist mArtist = (Artist) mItem;
            mSelectedId = mArtist.mArtistId;
            mSongName = null;
            mArtistName = mArtist.mArtistName;
            mSongList = MusicUtils.getSongListForArtist(getActivity(), mArtist.mArtistId);
        } else if (mItem instanceof Genre) {
            Genre mGenre = (Genre) mItem;
            mSelectedId = mGenre.mGenreId;
            mSongList = MusicUtils.getSongListForGenre(getActivity(), mGenre.mGenreId);
        } else if (mItem instanceof Playlist) {
            Playlist mPlaylist = (Playlist) mItem;
            mSelectedId = mPlaylist.mPlaylistId;
            if (mSelectedId == PlaylistLoader.FAVORITE_PLAYLIST_ID) {
                mSongList = MusicUtils.getSongListForFavorites(getActivity());
            } else if (mSelectedId == PlaylistLoader.LAST_ADDED_PLAYLIST_ID) {
                mSongList = MusicUtils.getSongListForLastAdded(getActivity());
            } else {
                mSongList = MusicUtils.getSongListForPlaylist(getActivity(), mPlaylist.mPlaylistId);
            }

        }

        // Play the selected songs
        menu.add(GROUP_ID, FragmentMenuItems.PLAY_SELECTION, Menu.NONE,
                getString(R.string.context_menu_play_selection));

        // Play the next song
        menu.add(GROUP_ID, FragmentMenuItems.PLAY_NEXT, Menu.NONE, getString(R.string.context_menu_play_next));

        // Add the song/album to the queue
        menu.add(GROUP_ID, FragmentMenuItems.ADD_TO_QUEUE, Menu.NONE, getString(R.string.add_to_queue));

        // Add the song to favorite's playlist
        menu.add(GROUP_ID, FragmentMenuItems.ADD_TO_FAVORITES, Menu.NONE, R.string.add_to_favorites);

        // Add the song/album to a playlist
        final SubMenu subMenu = menu.addSubMenu(GROUP_ID, FragmentMenuItems.ADD_TO_PLAYLIST, Menu.NONE,
                R.string.add_to_playlist);
        MusicUtils.makePlaylistMenu(getActivity(), GROUP_ID, subMenu, true);

        if (mItem instanceof Song) {
            menu.add(GROUP_ID, FragmentMenuItems.USE_AS_RINGTONE, Menu.NONE,
                    getString(R.string.context_menu_use_as_ringtone));
        }

        // More by artist
        menu.add(GROUP_ID, FragmentMenuItems.MORE_BY_ARTIST, Menu.NONE,
                getString(R.string.context_menu_more_by_artist));

        // Delete the album
        menu.add(GROUP_ID, FragmentMenuItems.DELETE, Menu.NONE, getString(R.string.context_menu_delete));
    }

    @Override
    public boolean onContextItemSelected(final android.view.MenuItem item) {
        if (item.getGroupId() == GROUP_ID) {
            final long[] songList = mSongList != null ? mSongList : new long[] { mSelectedId };

            switch (item.getItemId()) {
            case FragmentMenuItems.PLAY_SELECTION:
                MusicUtils.playAll(songList, 0, false);
                return true;
            case FragmentMenuItems.PLAY_NEXT:
                MusicUtils.playNext(songList);
                return true;
            case FragmentMenuItems.ADD_TO_QUEUE:
                MusicUtils.addToQueue(getActivity(), songList);
                return true;
            case FragmentMenuItems.ADD_TO_FAVORITES:
                onAddToFavorites();
                return true;
            case FragmentMenuItems.REMOVE_FROM_FAVORITES:
                onRemoveFromFavorites();
                return true;
            case FragmentMenuItems.NEW_PLAYLIST:
                CreateNewPlaylist.getInstance(songList).show(getFragmentManager(), "CreatePlaylist");
                return true;
            case FragmentMenuItems.PLAYLIST_SELECTED:
                final long playlistId = item.getIntent().getLongExtra("playlist", 0);
                MusicUtils.addToPlaylist(getActivity(), songList, playlistId);
                refresh();
                return true;
            case FragmentMenuItems.USE_AS_RINGTONE:
                MusicUtils.setRingtone(getActivity(), mSelectedId);
                return true;
            case FragmentMenuItems.DELETE:
                return onDelete(songList);
            case FragmentMenuItems.MORE_BY_ARTIST:
                long artistId = MusicUtils.getIdForArtist(getContext(), mArtistName);
                long[] tracks = MusicUtils.getSongListForArtist(getActivity(), artistId);
                NavUtils.openArtistProfile(getActivity(), mArtistName, tracks);
                return true;
            case FragmentMenuItems.REMOVE_FROM_PLAYLIST:
                return onRemoveFromPlaylist();
            case FragmentMenuItems.REMOVE_FROM_RECENT:
                return onRemoveFromRecent();
            default:
                break;
            }
        }
        return super.onContextItemSelected(item);
    }

    private boolean onRemoveFromRecent() {
        RecentStore.getInstance(getActivity()).removeItem(mSelectedId);
        MusicUtils.refresh();
        restartLoader(true);
        return true;
    }

    private boolean onDelete(long[] songList) {
        if (songList == null || songList.length == 0) {
            return false;
        }

        String title = getResources().getString(R.string.unknown);

        if (mItem instanceof Song) {
            title = ((Song) mItem).mSongName;
        } else if (mItem instanceof Album) {
            title = ((Album) mItem).mAlbumName;
        } else if (mItem instanceof Artist) {
            title = ((Artist) mItem).mArtistName;
        }

        DeleteDialog.newInstance(title, songList, null)
                .setOnDeleteCallback(new DeleteDialog.DeleteDialogCallback() {
                    @Override
                    public void onDelete(long[] id) {
                        restartLoader(true);
                        refresh();
                    }
                }).show(getFragmentManager(), "DeleteDialog");
        return true;
    }

    private boolean onRemoveFromPlaylist() {
        mAdapter.remove(mItem);
        mAdapter.notifyDataSetChanged();
        if (mItem instanceof Song) {
            Song song = (Song) mItem;
            MusicUtils.removeFromPlaylist(getActivity(), song.mSongId, mPlaylistId);
            restartLoader(true);
            return true;
        }
        return false;
    }

    private void onAddToFavorites() {
        if (mSongList != null) {
            int added = 0;
            for (Long songId : mSongList) {
                try {
                    final Song song = MusicUtils.getSong(getActivity(), songId);
                    if (song != null) {
                        FavoritesStore.getInstance(getActivity()).addSongId(songId, song.mSongName, song.mAlbumName,
                                song.mArtistName);
                        added++;
                    }
                } catch (Throwable ignored) {
                    ignored.printStackTrace();
                }
            }
            if (added > 0) {
                final String message = getResources().getQuantityString(R.plurals.NNNtrackstoplaylist, added,
                        added);
                AppMsg.makeText(getActivity(), message, AppMsg.STYLE_CONFIRM).show();
            }
        } else if (mSelectedId != -1) {
            FavoritesStore.getInstance(getActivity()).addSongId(mSelectedId, mSongName, mAlbumName, mArtistName);
        }
    }

    private void onRemoveFromFavorites() {
        mAdapter.remove(mItem);
        mAdapter.notifyDataSetChanged();
        FavoritesStore.getInstance(getActivity()).removeItem(mSelectedId);
        refresh();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onActivityCreated(final Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // Enable the options menu
        setHasOptionsMenu(true);
        initLoader();
    }

    @Override
    public void onSaveInstanceState(final Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putAll(getArguments() != null ? getArguments() : new Bundle());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onLoadFinished(final Loader<List<I>> loader, final List<I> data) {
        // Check for any errors
        if (data == null || data.isEmpty()) {
            mAdapter.unload();
            mAdapter.notifyDataSetChanged();

            // Set the empty text
            final TextView empty = (TextView) mRootView.findViewById(R.id.empty);
            if (empty != null) {
                empty.setText(getString(R.string.empty_music));
                if (isSimpleLayout()) {
                    mListView.setEmptyView(empty);
                } else {
                    mGridView.setEmptyView(empty);
                }
            }
            return;
        }

        if (mAdapter == null) {
            mAdapter = createAdapter();
            if (isSimpleLayout()) {
                mListView.setAdapter(mAdapter);
            } else {
                mGridView.setAdapter(mAdapter);
            }
        } else {
            mAdapter.unload();
        }

        // Start fresh
        if (mAdapter != null) {
            mAdapter.setDataList(data);

            mAdapter.setNotifyOnChange(false);
            for (final I item : data) {
                mAdapter.add(item);
            }
            mAdapter.setNotifyOnChange(true);

            if (mAdapter instanceof ApolloFragmentAdapter.Cacheable) {
                ((ApolloFragmentAdapter.Cacheable) mAdapter).buildCache();
            }

            mAdapter.notifyDataSetChanged();
        }
    }

    @Override
    public void onLoaderReset(final Loader<List<I>> loader) {
        // Clear the data in the adapter
        if (mAdapter != null) {
            mAdapter.unload();
        }
    }

    /**
     * Restarts the loader.
     * (Don't do so until 10 seconds later if you refreshed already)
     */
    public void refresh() {
        // Scroll to the stop of the list before restarting the loader.
        // Otherwise, if the user has scrolled enough to move the header, it
        // becomes misplaced and needs to be reset.
        if (mListView != null) {
            mListView.setSelection(0);
        } else if (mGridView != null) {
            mGridView.setSelection(0);
        }

        if (mAdapter != null) {
            mAdapter.clear();
        }

        restartLoader(); // this won't be executed if it was recently called. no risk of endless loop.

        if (mAdapter != null) {
            mAdapter.notifyDataSetChanged();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mAdapter != null) {
            mAdapter.flush();
        }
    }

    public void restartLoader() {
        restartLoader(false);
    }

    public boolean restartLoader(boolean force) {
        if (force || (System.currentTimeMillis() - lastRestartLoader) >= 5000) {
            lastRestartLoader = System.currentTimeMillis();
            try {
                getLoaderManager().restartLoader(LOADER_ID, getArguments(), this);
                return true;
            } catch (Throwable t) {
                return false;
            }
        }
        return false;
    }

    private void initLoader() {
        final Intent intent = getActivity().getIntent();
        if (intent != null && intent.getExtras() != null) {
            getLoaderManager().initLoader(LOADER_ID, intent.getExtras(), this);
        } else {
            restartLoader(true);
        }
    }

    public void onMetaChanged() {
        restartLoader();
    }

    protected boolean isSimpleLayout() {
        //boolean r = PreferenceUtils.getInstance(getActivity()).isSimpleLayout(getLayoutTypeName());
        return true;
    }

    protected boolean isDetailedLayout() {
        return PreferenceUtils.getInstance(getActivity()).isDetailedLayout(getLayoutTypeName());
    }

    /**
     * Sets up the grid view
     */
    private void initGridView() {
        if (mRootView == null) {
            throw new RuntimeException("initGridView(): mRootView == null");
        }
        // Initialize the grid
        mGridView = (GridView) mRootView.findViewById(R.id.grid_base);

        if (mGridView != null && mAdapter != null) {
            // Set the data behind the grid
            mGridView.setAdapter(mAdapter);
            // Set up the helpers
            initAbsListView(mGridView);
        }

        if (ApolloUtils.isLandscape(getActivity())) {
            if (isDetailedLayout()) {
                if (mAdapter != null) {
                    mAdapter.setLoadExtraData(true);
                }
                mGridView.setNumColumns(2);
            } else {
                mGridView.setNumColumns(4);
            }
        } else {
            if (isDetailedLayout()) {
                if (mAdapter != null) {
                    mAdapter.setLoadExtraData(true);
                }
                mGridView.setNumColumns(1);
            } else {
                mGridView.setNumColumns(2);
            }
        }
    }

    /**
     * Sets up various helpers for both the list and grid
     *
     * @param list The list or grid
     */
    private void initAbsListView(final AbsListView list) {
        // Release any references to the recycled Views
        list.setRecyclerListener(new RecycleHolder());
        // Listen for ContextMenus to be created
        list.setOnCreateContextMenuListener(this);
        // Show the albums and songs from the selected artist
        list.setOnItemClickListener(this);

        // To help make scrolling smooth
        if (mProfileTabCarousel != null) {
            list.setOnScrollListener(new VerticalScrollListener(null, mProfileTabCarousel, 0));
            // Remove the scrollbars and padding for the fast scroll
            list.setVerticalScrollBarEnabled(false);
            list.setFastScrollEnabled(false);
            list.setPadding(0, 0, 0, 0);
        }
    }

    /**
     * Sets up the list view
     */
    protected void initListView() {
        if (mRootView == null) {
            throw new RuntimeException("initListView(): mRootView == null");
        }
        // Initialize the grid
        mListView = (ListView) mRootView.findViewById(R.id.list_base);
        // Set the data behind the list
        if (mAdapter != null) {
            mListView.setAdapter(mAdapter);
        }
        // Set up the helpers
        initAbsListView(mListView);
    }

    /**
     * Pause disk cache access to ensure smoother scrolling
     */
    final VerticalScrollListener.ScrollableHeader mScrollableHeader = new VerticalScrollListener.ScrollableHeader() {
        @Override
        public void onScrollStateChanged(final AbsListView view, final int scrollState) {
            // Pause disk cache access to ensure smoother scrolling
            if (mAdapter == null) {
                return;
            }
            mAdapter.setPauseDiskCache(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING
                    || scrollState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);

        }
    };

    /**
     * @return The position of an item in the list or grid based on the id of
     *         the currently playing album.
     */
    private int getItemPositionByAlbum() {
        final long albumId = MusicUtils.getCurrentAlbumId();
        if (mAdapter == null) {
            return 0;
        }
        for (int i = 0; i < mAdapter.getCount(); i++) {
            if (((Album) mAdapter.getItem(i)).mAlbumId == albumId) {
                return i;
            }
        }
        return 0;
    }

    /**
     * Scrolls the list to the currently playing album when the user touches the
     * header in the {@link TitlePageIndicator}.
     */
    public void scrollToCurrentAlbum() {
        final int currentAlbumPosition = getItemPositionByAlbum();
        if (currentAlbumPosition != 0) {
            if (isSimpleLayout()) {
                mListView.setSelection(currentAlbumPosition);
            } else {
                mGridView.setSelection(currentAlbumPosition);
            }
        }
    }

    /**
     * Scrolls the list to the currently playing song when the user touches the
     * header in the {@link TitlePageIndicator}.
     */
    public void scrollToCurrentSong() {
        final int currentSongPosition = getItemPositionBySong();
        if (currentSongPosition != 0) {
            mListView.setSelection(currentSongPosition);
        }
    }

    /**
     * @return The position of an item in the list based on the name of the
     *         currently playing song.
     */
    private int getItemPositionBySong() {
        final long trackId = MusicUtils.getCurrentAudioId();
        if (mAdapter == null) {
            return 0;
        }
        for (int i = 0; i < mAdapter.getCount(); i++) {
            if (((Song) mAdapter.getItem(i)).mSongId == trackId) {
                return i;
            }
        }
        return 0;
    }
}