com.audiokernel.euphonyrmt.fragments.BrowseFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.audiokernel.euphonyrmt.fragments.BrowseFragment.java

Source

/*
 * Copyright (C) 2010-2014 The MPDroid Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.audiokernel.euphonyrmt.fragments;

import com.audiokernel.euphonyrmt.MPDApplication;
import com.audiokernel.euphonyrmt.R;
import com.audiokernel.euphonyrmt.adapters.ArrayIndexerAdapter;
import com.audiokernel.euphonyrmt.helpers.MPDAsyncHelper.AsyncExecListener;
import com.audiokernel.euphonyrmt.library.SimpleLibraryActivity;
import com.audiokernel.euphonyrmt.tools.Tools;

import org.a0z.mpd.MPDCommand;
import org.a0z.mpd.MPDStatus;
import org.a0z.mpd.exception.MPDException;
import org.a0z.mpd.item.AbstractAlbum;
import org.a0z.mpd.item.AbstractMusic;
import org.a0z.mpd.item.Album;
import org.a0z.mpd.item.Artist;
import org.a0z.mpd.item.Item;
import org.a0z.mpd.item.Music;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.StringRes;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;

import java.io.IOException;
import java.util.List;

import uk.co.senab.actionbarpulltorefresh.library.ActionBarPullToRefresh;
import uk.co.senab.actionbarpulltorefresh.library.PullToRefreshLayout;
import uk.co.senab.actionbarpulltorefresh.library.listeners.OnRefreshListener;

public abstract class BrowseFragment extends Fragment
        implements OnMenuItemClickListener, AsyncExecListener, OnItemClickListener, OnRefreshListener {

    public static final int ADD = 0;

    public static final int ADD_PLAY = 2;

    public static final int ADD_REPLACE = 1;

    public static final int ADD_REPLACE_PLAY = 4;

    public static final int ADD_TO_PLAYLIST = 3;

    public static final int GOTO_ARTIST = 5;

    public static final int MAIN = 0;

    public static final int PLAYLIST = 3;

    public static final int POPUP_COVER_BLACKLIST = 10;

    public static final int POPUP_COVER_SELECTIVE_CLEAN = 11;

    private static final int MIN_ITEMS_BEFORE_FASTSCROLL = 50;

    private static final String TAG = "BrowseFragment";

    protected final MPDApplication mApp = MPDApplication.getInstance();

    final String mContext;

    final int mIrAdd;

    final int mIrAdded;

    protected List<? extends Item> mItems = null;

    protected int mJobID = -1;

    protected AbsListView mList;

    protected TextView mLoadingTextView;

    protected View mLoadingView;

    protected View mNoResultView;

    protected PullToRefreshLayout mPullToRefreshLayout;

    private boolean mFirstUpdateDone = false;

    protected BrowseFragment(@StringRes final int rAdd, @StringRes final int rAdded, final String pContext) {
        super();
        mIrAdd = rAdd;
        mIrAdded = rAdded;

        mContext = pContext;

        setHasOptionsMenu(false);
    }

    protected abstract void add(Item item, boolean replace, boolean play);

    protected abstract void add(Item item, String playlist);

    private void addAndReplace(final MenuItem item) {
        final AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();

        mApp.oMPDAsyncHelper.execAsync(new Runnable() {
            @Override
            public void run() {
                boolean replace = false;
                boolean play = false;
                switch (item.getGroupId()) {
                case ADD_REPLACE_PLAY:
                    replace = true;
                    play = true;
                    break;
                case ADD_REPLACE:
                    replace = true;
                    break;
                case ADD_PLAY:
                    final MPDStatus status = mApp.oMPDAsyncHelper.oMPD.getStatus();

                    /**
                     * Let the user know if we're not going to play the added music.
                     */
                    if (status.isRandom() && status.isState(MPDStatus.STATE_PLAYING)) {
                        Tools.notifyUser(R.string.notPlayingInRandomMode);
                    } else {
                        play = true;
                    }
                    break;
                default:
                    break;
                }
                add(mItems.get((int) info.id), replace, play);
            }
        });
    }

    private void addToPlaylist(final MenuItem item) {
        final EditText input = new EditText(getActivity());
        final int id = item.getOrder();
        if (item.getItemId() == 0) {
            new AlertDialog.Builder(getActivity()).setTitle(R.string.playlistName)
                    .setMessage(R.string.newPlaylistPrompt).setView(input)
                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(final DialogInterface dialog, final int which) {
                            final String name = input.getText().toString().trim();
                            if (!name.isEmpty()) {
                                mApp.oMPDAsyncHelper.execAsync(new Runnable() {
                                    @Override
                                    public void run() {
                                        add(mItems.get(id), name);
                                    }
                                });
                            }
                        }
                    }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(final DialogInterface dialog, final int which) {
                            // Do nothing.
                        }
                    }).show();
        } else {
            add(mItems.get(id), item.getTitle().toString());
        }
    }

    @Override
    public void asyncExecSucceeded(final int jobID) {
        if (mJobID == jobID) {
            updateFromItems();
        }

    }

    protected void asyncUpdate() {

    }

    // Override if you want setEmptyView to be called on the list even if you have a header
    protected boolean forceEmptyView() {
        return false;
    }

    protected ListAdapter getCustomListAdapter() {
        return new ArrayIndexerAdapter(getActivity(), R.layout.simple_list_item_1, mItems);
    }

    /*
     * Override this to display a custom loading text
     */
    @StringRes
    public int getLoadingText() {
        return R.string.loading;
    }

    /**
     * Should return the minimum number of songs in the queue before the
     * fastscroll thumb is shown
     */
    protected int getMinimumItemsCountBeforeFastscroll() {
        return MIN_ITEMS_BEFORE_FASTSCROLL;
    }

    /*
     * Override this to display a custom activity title
     */
    public String getTitle() {
        return "";
    }

    @Override
    public void onActivityCreated(final Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        final ActionBarActivity activity = (ActionBarActivity) getActivity();
        if (activity != null) {
            final ActionBar actionBar = activity.getSupportActionBar();
            if (actionBar != null) {
                actionBar.setDisplayHomeAsUpEnabled(true);
            }
        }
    }

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

        final int index = (int) info.id;
        if (index >= 0 && mItems.size() > index) {
            menu.setHeaderTitle(mItems.get((int) info.id).toString());
            // If in simple mode, show "Play" (add, replace & play), "Add to queue" and "Add to playlist"
            if (mApp.isInSimpleMode()) {
                final MenuItem playItem = menu.add(ADD_REPLACE_PLAY, ADD_REPLACE_PLAY, 0, R.string.play);
                playItem.setOnMenuItemClickListener(this);
                final MenuItem addItem = menu.add(ADD, ADD, 0, R.string.addToQueue);
                addItem.setOnMenuItemClickListener(this);
            } else {
                final MenuItem addItem = menu.add(ADD, ADD, 0, mIrAdd);
                addItem.setOnMenuItemClickListener(this);
                final MenuItem addAndReplaceItem = menu.add(ADD_REPLACE, ADD_REPLACE, 0, R.string.addAndReplace);
                addAndReplaceItem.setOnMenuItemClickListener(this);
                final MenuItem addAndReplacePlayItem = menu.add(ADD_REPLACE_PLAY, ADD_REPLACE_PLAY, 0,
                        R.string.addAndReplacePlay);
                addAndReplacePlayItem.setOnMenuItemClickListener(this);
                final MenuItem addAndPlayItem = menu.add(ADD_PLAY, ADD_PLAY, 0, R.string.addAndPlay);
                addAndPlayItem.setOnMenuItemClickListener(this);
            }

            if (R.string.addPlaylist != mIrAdd && R.string.addStream != mIrAdd
                    && mApp.oMPDAsyncHelper.oMPD.isCommandAvailable(MPDCommand.MPD_CMD_LISTPLAYLISTS)) {

                int id = 0;
                final SubMenu playlistMenu = menu.addSubMenu(R.string.addToPlaylist);
                MenuItem item = playlistMenu.add(ADD_TO_PLAYLIST, id++, (int) info.id, R.string.newPlaylist);
                item.setOnMenuItemClickListener(this);

                try {
                    final List<Item> playlists = mApp.oMPDAsyncHelper.oMPD.getPlaylists();

                    if (null != playlists) {
                        for (final Item pl : playlists) {
                            item = playlistMenu.add(ADD_TO_PLAYLIST, id++, (int) info.id, pl.getName());
                            item.setOnMenuItemClickListener(this);
                        }
                    }
                } catch (final IOException | MPDException e) {
                    Log.e(TAG, "Failed to parse playlists.", e);
                }
            }
            final MenuItem gotoArtistItem = menu.add(GOTO_ARTIST, GOTO_ARTIST, 0, R.string.goToArtist);
            gotoArtistItem.setOnMenuItemClickListener(this);

        }
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
            final Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.browse, container, false);
        mList = (AbsListView) view.findViewById(R.id.list);
        registerForContextMenu(mList);
        mList.setOnItemClickListener(this);
        mLoadingView = view.findViewById(R.id.loadingLayout);
        mLoadingTextView = (TextView) view.findViewById(R.id.loadingText);
        mNoResultView = view.findViewById(R.id.noResultLayout);
        mLoadingTextView.setText(getLoadingText());
        mPullToRefreshLayout = (PullToRefreshLayout) view.findViewById(R.id.pullToRefresh);

        return view;
    }

    @Override
    public void onDestroy() {
        try {
            mApp.oMPDAsyncHelper.removeAsyncExecListener(this);
        } catch (final Exception e) {
            Log.e(TAG, "Error while destroying BrowseFragment", e);
        }
        super.onDestroy();
    }

    @Override
    public void onDestroyView() {
        // help out the GC; imitated from ListFragment source
        mLoadingView = null;
        mLoadingTextView = null;
        mNoResultView = null;
        super.onDestroyView();
    }

    @Override
    public boolean onMenuItemClick(final MenuItem item) {
        switch (item.getGroupId()) {
        case ADD_REPLACE_PLAY:
        case ADD_REPLACE:
        case ADD:
        case ADD_PLAY:
            addAndReplace(item);
            break;
        case ADD_TO_PLAYLIST:
            addToPlaylist(item);
            break;
        case GOTO_ARTIST:
            final AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
            final Object selectedItem = mItems.get((int) info.id);
            final Intent intent = new Intent(getActivity(), SimpleLibraryActivity.class);
            Artist artist = null;

            if (selectedItem instanceof Album) {
                artist = ((AbstractAlbum) selectedItem).getArtist();
            } else if (selectedItem instanceof Artist) {
                artist = (Artist) selectedItem;
            } else if (selectedItem instanceof Music) {
                artist = new Artist(((AbstractMusic) selectedItem).getAlbumArtistOrArtist());
            }

            if (artist != null) {
                intent.putExtra("artist", artist);
                startActivityForResult(intent, -1);
            }
            break;
        default:
            final String name = item.getTitle().toString();
            final int id = item.getOrder();
            mApp.oMPDAsyncHelper.execAsync(new Runnable() {
                @Override
                public void run() {
                    add(mItems.get(id), name);
                }
            });
            break;
        }
        return false;
    }

    @Override
    public void onRefreshStarted(final View view) {
        mPullToRefreshLayout.setRefreshComplete();
        updateList();
    }

    @Override
    public void onStart() {
        super.onStart();
        mApp.setActivity(getActivity());
        if (!mFirstUpdateDone) {
            mFirstUpdateDone = true;
            updateList();
        }
    }

    @Override
    public void onStop() {
        mApp.unsetActivity(getActivity());
        super.onStop();
    }

    @Override
    public void onViewCreated(final View view, final Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        if (mItems != null) {
            mList.setAdapter(getCustomListAdapter());
        }
        refreshFastScrollStyle();
        if (mPullToRefreshLayout != null) {
            ActionBarPullToRefresh.from(getActivity()).allChildrenArePullable().listener(this)
                    .setup(mPullToRefreshLayout);
        }
    }

    /**
     * This method is used for the fastcroll visibility decision.<br/>
     * Don't override this if you want to change the fastscroll style, override
     * {@link #refreshFastScrollStyle(boolean)} instead.
     */
    protected void refreshFastScrollStyle() {
        refreshFastScrollStyle(mItems != null && mItems.size() >= getMinimumItemsCountBeforeFastscroll());
    }

    /**
     * This is required because setting the fast scroll prior to KitKat was
     * important because of a bug. This bug has since been corrected, but the
     * opposite order is now required or the fast scroll will not show.
     *
     * @param shouldShowFastScroll If the fast scroll should be shown or not
     */
    protected void refreshFastScrollStyle(final boolean shouldShowFastScroll) {
        if (shouldShowFastScroll) {
            refreshFastScrollStyle(View.SCROLLBARS_INSIDE_INSET, true);
        } else {
            refreshFastScrollStyle(View.SCROLLBARS_INSIDE_OVERLAY, false);
        }
    }

    /**
     * This is a helper method to workaround shortcomings of the fast scroll API.
     *
     * @param scrollbarStyle  The {@code View} scrollbar style.
     * @param isAlwaysVisible The visibility of the scrollbar.
     */
    final void refreshFastScrollStyle(final int scrollbarStyle, final boolean isAlwaysVisible) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            mList.setFastScrollAlwaysVisible(isAlwaysVisible);
            mList.setScrollBarStyle(scrollbarStyle);
        } else {
            mList.setScrollBarStyle(scrollbarStyle);
            mList.setFastScrollAlwaysVisible(isAlwaysVisible);
        }
    }

    public void scrollToTop() {
        try {
            mList.setSelection(-1);
        } catch (final Exception e) {
            // What if the list is empty or some other bug ? I don't want any
            // crashes because of that
        }
    }

    public void setActivityTitle(final CharSequence title) {
        getActivity().setTitle(title);
    }

    /**
     * Update the view from the items list if items is set.
     */
    public void updateFromItems() {
        if (getView() == null) {
            // The view has been destroyed, bail.
            return;
        }
        if (mPullToRefreshLayout != null) {
            mPullToRefreshLayout.setEnabled(true);
        }
        if (mItems != null) {
            mList.setAdapter(getCustomListAdapter());
        }
        try {
            if (forceEmptyView() || mList instanceof ListView && ((ListView) mList).getHeaderViewsCount() == 0) {
                mList.setEmptyView(mNoResultView);
            } else {
                if (mItems == null || mItems.isEmpty()) {
                    mNoResultView.setVisibility(View.VISIBLE);
                }
            }
        } catch (final Exception e) {
            Log.e(TAG, "Exception.", e);
        }

        mLoadingView.setVisibility(View.GONE);
        refreshFastScrollStyle();
    }

    public void updateList() {
        mList.setAdapter(null);
        mNoResultView.setVisibility(View.GONE);
        mLoadingView.setVisibility(View.VISIBLE);
        if (mPullToRefreshLayout != null) {
            mPullToRefreshLayout.setEnabled(false);
        }

        // Loading Artists asynchronous...
        mApp.oMPDAsyncHelper.addAsyncExecListener(this);
        mJobID = mApp.oMPDAsyncHelper.execAsync(new Runnable() {
            @Override
            public void run() {
                asyncUpdate();
            }
        });
    }
}