/*
* Copyright (C) 2014 Saravan Pantham
*
* 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.aniruddhc.acemusic.player.Drawers;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.content.LocalBroadcastManager;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.ScaleAnimation;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.aniruddhc.acemusic.player.Helpers.TypefaceHelper;
import com.aniruddhc.acemusic.player.Helpers.UIElementsHelper;
import com.aniruddhc.acemusic.player.NowPlayingActivity.NowPlayingActivity;
import com.aniruddhc.acemusic.player.R;
import com.aniruddhc.acemusic.player.Services.AudioPlaybackService;
import com.aniruddhc.acemusic.player.Utils.Common;
import com.mobeta.android.dslv.DragSortListView;
import com.mobeta.android.dslv.SimpleFloatViewManager;
public class QueueDrawerFragment extends Fragment {
private Context mContext;
private Common mApp;
private RelativeLayout mMiniPlayerLayout;
private ImageView mMiniPlayerAlbumArt;
private RelativeLayout mPlayPauseBackground;
private ImageButton mPlayPauseButton;
private ImageButton mNextButton;
private ImageButton mPreviousButton;
private TextView mTitleText;
private TextView mSubText;
private DragSortListView mListView;
private QueueDrawerAdapter mListViewAdapter;
private TextView mEmptyInfoText;
private boolean mInitListViewParams = true;
private boolean mDrawerOpen = false;
@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mContext = getActivity();
mApp = (Common) mContext.getApplicationContext();
View rootView = inflater.inflate(R.layout.fragment_queue_drawer, null);
if (mApp.getCurrentTheme()==Common.LIGHT_THEME) {
rootView.setBackgroundColor(0xFFFFFFFF);
} else {
rootView.setBackgroundColor(0xFF191919);
}
mMiniPlayerLayout = (RelativeLayout) rootView.findViewById(R.id.queue_drawer_mini_player_layout);
mMiniPlayerAlbumArt = (ImageView) rootView.findViewById(R.id.queue_drawer_album_art);
mPlayPauseBackground = (RelativeLayout) rootView.findViewById(R.id.playPauseButtonBackground);
mPlayPauseButton = (ImageButton) rootView.findViewById(R.id.playPauseButton);
mNextButton = (ImageButton) rootView.findViewById(R.id.nextButton);
mPreviousButton = (ImageButton) rootView.findViewById(R.id.previousButton);
mTitleText = (TextView) rootView.findViewById(R.id.songName);
mSubText = (TextView) rootView.findViewById(R.id.artistAlbumName);
mListView = (DragSortListView) rootView.findViewById(R.id.queue_drawer_list_view);
mEmptyInfoText = (TextView) rootView.findViewById(R.id.queue_drawer_empty_text);
mPlayPauseBackground.setBackgroundResource(UIElementsHelper.getShadowedCircle(mContext));
mPlayPauseButton.setId(R.drawable.pause_light);
mTitleText.setTypeface(TypefaceHelper.getTypeface(mContext, "Roboto-Regular"));
mSubText.setTypeface(TypefaceHelper.getTypeface(mContext, "Roboto-Regular"));
mEmptyInfoText.setTypeface(TypefaceHelper.getTypeface(getActivity(), "Roboto-Regular"));
//Set the click listeners.
mMiniPlayerLayout.setOnClickListener(mOnClickMiniPlayer);
mPlayPauseBackground.setOnClickListener(playPauseClickListener);
mPlayPauseButton.setOnClickListener(playPauseClickListener);
mNextButton.setOnClickListener(mOnClickNextListener);
mPreviousButton.setOnClickListener(mOnClickPreviousListener);
//Restrict all touch events to this fragment.
rootView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
//KitKat translucent navigation/status bar.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
int navBarHeight = Common.getNavigationBarHeight(mContext);
if (mListView!=null) {
mListView.setPadding(0, 0, 0, navBarHeight);
mListView.setClipToPadding(false);
}
}
return rootView;
}
/**
* Broadcast receiver interface that will update this activity as necessary.
*/
BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle.containsKey(Common.UPDATE_PAGER_POSTIION)) {
//Update the queue fragment with the new song info.
initMiniPlayer();
initListViewAdapter(false);
}
//Updates the playback control buttons.
if (intent.hasExtra(Common.UPDATE_PLAYBACK_CONTROLS))
setPlayPauseButton();
if (bundle.containsKey(Common.SERVICE_STOPPING)) {
showEmptyTextView();
}
}
};
/**
* Helper method that checks whether the audio playback service
* is running or not.
*/
private void checkServiceRunning() {
if (mApp.isServiceRunning() && mApp.getService().getCursor()!=null) {
initMiniPlayer();
setPlayPauseButton();
initListViewAdapter(mInitListViewParams);
} else {
showEmptyTextView();
}
}
/**
* Initializes the mini player above the current queue.
*/
private void initMiniPlayer() {
mMiniPlayerLayout.setVisibility(View.VISIBLE);
mMiniPlayerAlbumArt.setImageBitmap(mApp.getService().getCurrentSong().getAlbumArt());
mTitleText.setText(mApp.getService().getCurrentSong().getTitle());
mSubText.setText(mApp.getService().getCurrentSong().getAlbum() + " - " +
mApp.getService().getCurrentSong().getArtist());
}
/**
* Initializes the drag sort list view.
*
* @param initViewParams Pass true if the ListView is being
* initialized for the very first time
* (dividers, background colors and other
* layout settings will be applied). Pass
* false if the list just needs to be updated
* with the current song.
*/
private void initListViewAdapter(boolean initViewParams) {
if (initViewParams) {
//Reset the initialization flag.
mInitListViewParams = false;
if (mApp.getCurrentTheme()==Common.DARK_THEME) {
mListView.setDivider(mContext.getResources().getDrawable(R.drawable.list_divider));
} else {
mListView.setDivider(mContext.getResources().getDrawable(R.drawable.list_divider_light));
}
mListView.setDividerHeight(1);
mListView.setFastScrollEnabled(true);
//KitKat ListView margins.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//Calculate navigation bar height.
int navigationBarHeight = 0;
int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
navigationBarHeight = getResources().getDimensionPixelSize(resourceId);
}
mListView.setClipToPadding(false);
mListView.setPadding(0, 0, 0, navigationBarHeight);
}
}
mListViewAdapter = new QueueDrawerAdapter(mContext, mApp.getService().getPlaybackIndecesList());
mListView.setAdapter(mListViewAdapter);
mListView.setOnItemClickListener(onClick);
mListView.setDropListener(onDrop);
mListView.setRemoveListener(onRemove);
SimpleFloatViewManager simpleFloatViewManager = new SimpleFloatViewManager(mListView);
simpleFloatViewManager.setBackgroundColor(Color.TRANSPARENT);
mListView.setFloatViewManager(simpleFloatViewManager);
mListView.setVisibility(View.VISIBLE);
mEmptyInfoText.setVisibility(View.INVISIBLE);
/*
* If the drawer is open, the user is probably scrolling through
* the list already, so don't move the list to the new position.
*/
if (!isDrawerOpen())
mListView.setSelection(mApp.getService().getCurrentSongIndex());
}
/**
* Sets the play/pause button states.
*/
private void setPlayPauseButton() {
if (mApp.isServiceRunning()) {
if (mApp.getService().isPlayingMusic())
animatePlayToPause();
else
animatePauseToPlay();
}
}
/**
* Animates the play button to a pause button.
*/
private void animatePlayToPause() {
//Check to make sure the current icon is the play icon.
if (mPlayPauseButton.getId()!=R.drawable.play_light)
return;
//Fade out the play button.
final ScaleAnimation scaleOut = new ScaleAnimation(1.0f, 0.0f, 1.0f, 0.0f,
mPlayPauseButton.getWidth()/2,
mPlayPauseButton.getHeight()/2);
scaleOut.setDuration(150);
scaleOut.setInterpolator(new AccelerateInterpolator());
//Scale in the pause button.
final ScaleAnimation scaleIn = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f,
mPlayPauseButton.getWidth()/2,
mPlayPauseButton.getHeight()/2);
scaleIn.setDuration(150);
scaleIn.setInterpolator(new DecelerateInterpolator());
scaleOut.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mPlayPauseButton.setImageResource(R.drawable.pause_light);
mPlayPauseButton.setPadding(0, 0, 0, 0);
mPlayPauseButton.startAnimation(scaleIn);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
scaleIn.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mPlayPauseButton.setScaleX(1.0f);
mPlayPauseButton.setScaleY(1.0f);
mPlayPauseButton.setId(R.drawable.pause_light);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mPlayPauseButton.startAnimation(scaleOut);
}
/**
* Animates the pause button to a play button.
*/
private void animatePauseToPlay() {
//Check to make sure the current icon is the pause icon.
if (mPlayPauseButton.getId()!=R.drawable.pause_light)
return;
//Scale out the pause button.
final ScaleAnimation scaleOut = new ScaleAnimation(1.0f, 0.0f, 1.0f, 0.0f,
mPlayPauseButton.getWidth()/2,
mPlayPauseButton.getHeight()/2);
scaleOut.setDuration(150);
scaleOut.setInterpolator(new AccelerateInterpolator());
//Scale in the play button.
final ScaleAnimation scaleIn = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f,
mPlayPauseButton.getWidth()/2,
mPlayPauseButton.getHeight()/2);
scaleIn.setDuration(150);
scaleIn.setInterpolator(new DecelerateInterpolator());
scaleOut.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mPlayPauseButton.setImageResource(R.drawable.play_light);
mPlayPauseButton.setPadding(0, 0, -5, 0);
mPlayPauseButton.startAnimation(scaleIn);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
scaleIn.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mPlayPauseButton.setScaleX(1.0f);
mPlayPauseButton.setScaleY(1.0f);
mPlayPauseButton.setId(R.drawable.play_light);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mPlayPauseButton.startAnimation(scaleOut);
}
/**
* Click listener for the play/pause button.
*/
private View.OnClickListener playPauseClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
//BZZZT! Give the user a brief haptic feedback touch response.
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
//Update the playback UI elements.
if (mApp.getService().isPlayingMusic())
animatePauseToPlay();
else
animatePlayToPause();
/*
* Toggle the playback state in a separate thread. This
* will allow the play/pause button animation to remain
* buttery smooth.
*/
new AsyncTask() {
@Override
protected Object doInBackground(Object[] params) {
mApp.getService().togglePlaybackState();
return null;
}
}.execute();
}
};
/**
* Click listener for the previous button.
*/
private View.OnClickListener mOnClickPreviousListener = new View.OnClickListener() {
@Override
public void onClick(View arg0) {
mApp.getService().skipToPreviousTrack();
}
};
/**
* Click listener for the next button.
*/
private View.OnClickListener mOnClickNextListener = new View.OnClickListener() {
@Override
public void onClick(View arg0) {
mApp.getService().skipToNextTrack();
}
};
/**
* Called if the audio playback service is not running.
*/
public void showEmptyTextView() {
mMiniPlayerLayout.setVisibility(View.GONE);
mListView.setVisibility(View.INVISIBLE);
mEmptyInfoText.setVisibility(View.VISIBLE);
}
/**
* Click listener for the mini player.
*/
private View.OnClickListener mOnClickMiniPlayer = new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mContext, NowPlayingActivity.class);
startActivity(intent);
}
};
/**
* Click listener for the ListView.
*/
private AdapterView.OnItemClickListener onClick = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (mApp.isServiceRunning())
mApp.getService().skipToTrack(position);
}
};
/**
* Drag and drop interface for the ListView.
*/
private DragSortListView.DropListener onDrop = new DragSortListView.DropListener() {
@Override
public void drop(int from, int to) {
if (from!=to) {
int fromItem = mListViewAdapter.getItem(from);
int toItem = mListViewAdapter.getItem(to);
mListViewAdapter.remove(fromItem);
mListViewAdapter.insert(fromItem, to);
//If the current song was reordered, change currentSongIndex and update the next song.
if (from==mApp.getService().getCurrentSongIndex()) {
mApp.getService().setCurrentSongIndex(to);
//Check which mediaPlayer is currently playing, and prepare the other mediaPlayer.
mApp.getService().prepareAlternateMediaPlayer();
return;
} else if (from > mApp.getService().getCurrentSongIndex() && to <= mApp.getService().getCurrentSongIndex()) {
//One of the next songs was moved to a position before the current song. Move currentSongIndex forward by 1.
mApp.getService().incrementCurrentSongIndex();
mApp.getService().incrementEnqueueReorderScalar();
//Check which mediaPlayer is currently playing, and prepare the other mediaPlayer.
mApp.getService().prepareAlternateMediaPlayer();
return;
} else if (from < mApp.getService().getCurrentSongIndex() && to==mApp.getService().getCurrentSongIndex()) {
/* One of the previous songs was moved to the current song's position (visually speaking,
* the new song will look like it was placed right after the current song.
*/
mApp.getService().decrementCurrentSongIndex();
mApp.getService().decrementEnqueueReorderScalar();
//Check which mediaPlayer is currently playing, and prepare the other mediaPlayer.
mApp.getService().prepareAlternateMediaPlayer();
return;
} else if (from < mApp.getService().getCurrentSongIndex() && to > mApp.getService().getCurrentSongIndex()) {
//One of the previous songs was moved to a position after the current song. Move currentSongIndex back by 1.
mApp.getService().decrementCurrentSongIndex();
mApp.getService().decrementEnqueueReorderScalar();
//Check which mediaPlayer is currently playing, and prepare the other mediaPlayer.
mApp.getService().prepareAlternateMediaPlayer();
return;
}
//If the next song was reordered, reload it with the new index.
if (mApp.getService().getPlaybackIndecesList().size() > (mApp.getService().getCurrentSongIndex()+1)) {
if (fromItem==mApp.getService().getPlaybackIndecesList().get(mApp.getService().getCurrentSongIndex()+1) ||
toItem==mApp.getService().getPlaybackIndecesList().get(mApp.getService().getCurrentSongIndex()+1)) {
//Check which mediaPlayer is currently playing, and prepare the other mediaPlayer.
mApp.getService().prepareAlternateMediaPlayer();
}
} else {
//Check which mediaPlayer is currently playing, and prepare the other mediaPlayer.
mApp.getService().prepareAlternateMediaPlayer();
}
}
//Fire a broadcast that notifies all listeners that the current queue order has changed.
String[] updateFlags = { Common.NEW_QUEUE_ORDER };
String[] flagValues = { "" };
mApp.broadcastUpdateUICommand(updateFlags, flagValues);
}
};
/**
* Click remove interface for the ListView.
*/
private DragSortListView.RemoveListener onRemove = new DragSortListView.RemoveListener() {
@Override
public void remove(int which) {
//Stop the service if we just removed the last (and only) song.
if (mApp.getService().getPlaybackIndecesList().size()==1) {
mContext.stopService(new Intent(mContext, AudioPlaybackService.class));
return;
}
//If the song that was removed is the next song, reload it.
if (mApp.getService().getPlaybackIndecesList().size() > (mApp.getService().getCurrentSongIndex()+1)) {
if (mListViewAdapter.getItem(which)==mApp.getService().getPlaybackIndecesList().get(mApp.getService().getCurrentSongIndex()+1)) {
//Check which mediaPlayer is currently playing, and prepare the other mediaPlayer.
mApp.getService().prepareAlternateMediaPlayer();
} else if (mListViewAdapter.getItem(which)==mApp.getService().getPlaybackIndecesList().get(mApp.getService().getCurrentSongIndex())) {
mApp.getService().incrementCurrentSongIndex();
mApp.getService().prepareMediaPlayer(mApp.getService().getCurrentSongIndex());
mApp.getService().decrementCurrentSongIndex();
} else if (mListViewAdapter.getItem(which) < mApp.getService().getPlaybackIndecesList().get(mApp.getService().getCurrentSongIndex())) {
mApp.getService().decrementCurrentSongIndex();
}
} else if (which==(mApp.getService().getPlaybackIndecesList().size()-1) &&
mApp.getService().getCurrentSongIndex()==(mApp.getService().getPlaybackIndecesList().size()-1)) {
//The current song was the last one and it was removed. Time to back up to the previous song.
mApp.getService().decrementCurrentSongIndex();
mApp.getService().prepareMediaPlayer(mApp.getService().getCurrentSongIndex());
} else {
//Check which mediaPlayer is currently playing, and prepare the other mediaPlayer.
mApp.getService().prepareAlternateMediaPlayer();
}
//Remove the item from the adapter.
mListViewAdapter.remove(mListViewAdapter.getItem(which));
}
};
@Override
public void onResume() {
super.onResume();
checkServiceRunning();
mPlayPauseBackground.setBackgroundResource(UIElementsHelper.getShadowedCircle(mContext));
mPlayPauseButton.setId(R.drawable.pause_light);
}
@Override
public void onStart() {
super.onStart();
LocalBroadcastManager.getInstance(mContext)
.registerReceiver((mReceiver), new IntentFilter(Common.UPDATE_UI_BROADCAST));
}
@Override
public void onStop() {
LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mReceiver);
super.onStop();
}
public boolean isDrawerOpen() {
return mDrawerOpen;
}
public void setIsDrawerOpen(boolean isOpen) {
mDrawerOpen = isOpen;
}
}