/* * Copyright (C) 2014 Fastboot Mobile, LLC. * * 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.fastbootmobile.encore.app.fragments; import android.app.Activity; import android.app.ActivityOptions; import android.content.Intent; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Process; import android.os.RemoteException; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.GridView; import com.fastbootmobile.encore.app.MainActivity; import com.fastbootmobile.encore.app.PlaylistActivity; import com.fastbootmobile.encore.app.R; import com.fastbootmobile.encore.app.adapters.PlaylistGridAdapter; import com.fastbootmobile.encore.app.adapters.PlaylistListAdapter; import com.fastbootmobile.encore.app.ui.MaterialTransitionDrawable; import com.fastbootmobile.encore.model.Album; import com.fastbootmobile.encore.model.Artist; import com.fastbootmobile.encore.model.Playlist; import com.fastbootmobile.encore.model.SearchResult; import com.fastbootmobile.encore.model.Song; import com.fastbootmobile.encore.providers.ILocalCallback; import com.fastbootmobile.encore.providers.IMusicProvider; import com.fastbootmobile.encore.providers.ProviderAggregator; import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator; import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator; import com.h6ah4i.android.widget.advrecyclerview.decoration.SimpleListDividerDecorator; import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager; import org.json.JSONException; import java.util.ArrayList; import java.util.List; /** * A simple {@link android.support.v4.app.Fragment} subclass, showing a list of playlists. * Use the {@link PlaylistListFragment#newInstance} factory method to * create an instance of this fragment. */ public class PlaylistListFragment extends Fragment implements ILocalCallback { private static final String TAG = "PlaylistListFragment"; private PlaylistListAdapter mAdapter; private PlaylistGridAdapter mGridAdapter; private LinearLayoutManager mLayoutManager; private RecyclerView mRecyclerView; private RecyclerViewDragDropManager mRecyclerViewDragDropManager; private RecyclerView.Adapter mWrappedAdapter; private Handler mHandler; private boolean mIsStandalone; private final ArrayList<Playlist> mPlaylistsUpdated = new ArrayList<>(); private Runnable mUpdateListRunnable = new Runnable() { @Override public void run() { synchronized (mPlaylistsUpdated) { if (mAdapter != null) { mAdapter.addAllUnique(mPlaylistsUpdated); } if (mGridAdapter != null) { mGridAdapter.addAllUnique(mPlaylistsUpdated); } mPlaylistsUpdated.clear(); } if (mAdapter != null && getActivity() != null) { try { mAdapter.sortList(getActivity().getApplicationContext()); } catch (JSONException e) { Log.e(TAG, "Unable to sort playlists list"); } mAdapter.notifyDataSetChanged(); } if (mGridAdapter != null) { mGridAdapter.notifyDataSetChanged(); } } }; private Runnable mDataChangedRunnable = new Runnable() { @Override public void run() { if (mGridAdapter != null) { mGridAdapter.notifyDataSetChanged(); } if (mAdapter != null) { mAdapter.notifyDataSetChanged(); } } }; /** * Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param isStandalone Whether this fragment is embedded in My Songs or is the Playlists section * @return A new instance of fragment PlaylistListFragment. */ public static PlaylistListFragment newInstance(boolean isStandalone) { PlaylistListFragment fragment = new PlaylistListFragment(); fragment.setIsStandalone(isStandalone); return fragment; } /** * Default constructor. Use {@link #newInstance(boolean)} to create an instance of this fragment */ public PlaylistListFragment() { mAdapter = new PlaylistListAdapter(); } /** * Sets whether or not the fragment is displayed standalone (root of an activity's contents) * or within another container (e.g. a viewpager contents). * @param isStandalone Whether this fragment is embedded in My Songs or is the Playlists section */ public void setIsStandalone(boolean isStandalone) { mIsStandalone = isStandalone; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHandler = new Handler(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View root = inflater.inflate(R.layout.fragment_playlist, container, false); if (root instanceof GridView) { // We're in landscape, and thus have a GridView mGridAdapter = new PlaylistGridAdapter(root.getContext().getApplicationContext()); mAdapter = null; } else { // We're in portrait with the recycler view mAdapter = new PlaylistListAdapter(); mGridAdapter = null; } return root; } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // If mAdapter isn't null, we're in portrait with the draggable list view. if (mAdapter != null) { mRecyclerView = (RecyclerView) view.findViewById(R.id.rvPlaylists); mLayoutManager = new LinearLayoutManager(getContext()); // drag & drop manager mRecyclerViewDragDropManager = new RecyclerViewDragDropManager(); //adapter mWrappedAdapter = mRecyclerViewDragDropManager.createWrappedAdapter(mAdapter); // wrap for dragging final GeneralItemAnimator animator = new RefactoredDefaultItemAnimator(); mRecyclerView.setLayoutManager(mLayoutManager); mRecyclerView.setAdapter(mWrappedAdapter); // requires *wrapped* adapter mRecyclerView.setItemAnimator(animator); // additional decorations mRecyclerView.addItemDecoration(new SimpleListDividerDecorator(getResources().getDrawable(R.drawable.list_divider), true)); mRecyclerViewDragDropManager.attachRecyclerView(mRecyclerView); if (!mIsStandalone) { mRecyclerView.setPadding(0, 0, 0, 0); } } else { // We're in landscape with the grid view GridView root = (GridView) view.findViewById(R.id.gvPlaylists); root.setAdapter(mGridAdapter); if (!mIsStandalone) { root.setPadding(0, 0, 0, 0); } // Setup the click listener root.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { MainActivity act = (MainActivity) getActivity(); PlaylistGridAdapter.ViewHolder tag = (PlaylistGridAdapter.ViewHolder) view.getTag(); Intent intent = PlaylistActivity.craftIntent(act, mGridAdapter.getItem(position), ((MaterialTransitionDrawable) tag.ivCover.getDrawable()).getFinalDrawable().getBitmap()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { ActivityOptions opt = ActivityOptions.makeSceneTransitionAnimation(getActivity(), tag.ivCover, "itemImage"); act.startActivity(intent, opt.toBundle()); } else { act.startActivity(intent); } } }); } } @Override public void onAttach(Activity activity) { super.onAttach(activity); if (mIsStandalone) { MainActivity mainActivity = (MainActivity) activity; mainActivity.onSectionAttached(MainActivity.SECTION_PLAYLISTS); } } @Override public void onResume() { super.onResume(); ProviderAggregator.getDefault().addUpdateCallback(this); updatePlaylists(); } @Override public void onPause() { super.onPause(); ProviderAggregator.getDefault().removeUpdateCallback(this); } private void updatePlaylists() { new GetPlaylistsTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @Override public void onSongUpdate(List<Song> s) { } @Override public void onAlbumUpdate(List<Album> a) { } @Override public void onPlaylistUpdate(final List<Playlist> p) { if (p != null) { synchronized (mPlaylistsUpdated) { mPlaylistsUpdated.addAll(p); } mHandler.removeCallbacks(mUpdateListRunnable); mHandler.post(mUpdateListRunnable); } } @Override public void onPlaylistRemoved(String ref) { Log.d(TAG, "Playlist removed: " + ref); if (ref != null) { synchronized (mPlaylistsUpdated) { for (Playlist playlist : mPlaylistsUpdated) { if (playlist.getRef().equals(ref)) { mPlaylistsUpdated.remove(playlist); break; } } } mAdapter.remove(ref); mHandler.removeCallbacks(mDataChangedRunnable); mHandler.post(mDataChangedRunnable); } } @Override public void onArtistUpdate(List<Artist> a) { } @Override public void onProviderConnected(final IMusicProvider provider) { new Thread() { public void run() { // HACK: Wait a bit for the provider to be ready try { Thread.sleep(1000); } catch (InterruptedException ignore) { } try { onPlaylistUpdate(provider.getPlaylists()); } catch (RemoteException e) { Log.e(TAG, "Cannot get playlists"); } } }.start(); } @Override public void onSearchResult(List<SearchResult> searchResult) { } private class GetPlaylistsTask extends AsyncTask<Void, Void, List<Playlist>> { @Override protected List<Playlist> doInBackground(Void... params) { Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND); return ProviderAggregator.getDefault().getAllPlaylists(); } @Override protected void onPostExecute(List<Playlist> playlists) { if (mAdapter != null) { mAdapter.clear(); mAdapter.addAllUnique(playlists); Activity activity = getActivity(); if (activity != null) { try { mAdapter.sortList(activity.getApplicationContext()); } catch (JSONException e) { Log.e(TAG, "Unable to sort playlists list"); } } mAdapter.notifyDataSetChanged(); } if (mGridAdapter != null) { mGridAdapter.clear(); mGridAdapter.addAllUnique(playlists); mGridAdapter.notifyDataSetChanged(); } } } }