package com.simplecity.amp_library.ui.fragments;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import com.jakewharton.rxbinding.widget.RxSeekBar;
import com.jakewharton.rxbinding.widget.SeekBarChangeEvent;
import com.jakewharton.rxbinding.widget.SeekBarProgressChangeEvent;
import com.jakewharton.rxbinding.widget.SeekBarStartChangeEvent;
import com.jakewharton.rxbinding.widget.SeekBarStopChangeEvent;
import com.simplecity.amp_library.R;
import com.simplecity.amp_library.lyrics.LyricsFragment;
import com.simplecity.amp_library.model.Song;
import com.simplecity.amp_library.playback.MusicService;
import com.simplecity.amp_library.ui.activities.MainActivity;
import com.simplecity.amp_library.ui.presenters.PlayerPresenter;
import com.simplecity.amp_library.ui.views.PlayPauseView;
import com.simplecity.amp_library.ui.views.PlayerView;
import com.simplecity.amp_library.ui.views.RepeatingImageButton;
import com.simplecity.amp_library.ui.views.SizableSeekBar;
import com.simplecity.amp_library.utils.ColorUtils;
import com.simplecity.amp_library.utils.DrawableUtils;
import com.simplecity.amp_library.utils.MusicUtils;
import com.simplecity.amp_library.utils.StringUtils;
import com.simplecity.amp_library.utils.ThemeUtils;
import java.util.concurrent.TimeUnit;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.subscriptions.CompositeSubscription;
public class PlayerFragment extends BaseFragment implements PlayerView {
private final String TAG = ((Object) this).getClass().getSimpleName();
private SizableSeekBar seekBar;
private boolean isSeeking;
private PlayPauseView playPauseView;
private ImageButton shuffleButton;
private ImageButton repeatButton;
private RepeatingImageButton nextButton;
private RepeatingImageButton prevButton;
FloatingActionButton fab;
private TextView artist;
private TextView album;
private TextView track;
private TextView currentTime;
private TextView totalTime;
private TextView queuePosition;
private View textViewContainer;
private View buttonContainer;
private View bottomView;
private SharedPreferences sharedPreferences;
private static final String QUEUE_FRAGMENT = "queue_fragment";
private static final String QUEUE_PAGER_FRAGMENT = "queue_pager_fragment";
private static final String LYRICS_FRAGMENT = "lyrics_fragment";
private SharedPreferences.OnSharedPreferenceChangeListener mSharedPreferenceChangeListener;
boolean fabIsAnimating = false;
private View dragView;
private CompositeSubscription subscriptions;
private PlayerPresenter presenter = new PlayerPresenter();
public PlayerFragment() {
}
public static PlayerFragment newInstance() {
PlayerFragment playerFragment = new PlayerFragment();
Bundle args = new Bundle();
playerFragment.setArguments(args);
return playerFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this.getActivity());
mSharedPreferenceChangeListener = (sharedPreferences, key) -> {
if (key.equals("pref_theme_highlight_color") || key.equals("pref_theme_accent_color") || key.equals("pref_theme_white_accent")) {
themeUIComponents();
}
};
sharedPreferences.registerOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_player, container, false);
bottomView = rootView.findViewById(R.id.bottom_view);
playPauseView = (PlayPauseView) rootView.findViewById(R.id.play);
playPauseView.setOnClickListener(v -> {
playPauseView.toggle();
playPauseView.postDelayed(() -> presenter.togglePlayback(), 200);
});
repeatButton = (ImageButton) rootView.findViewById(R.id.repeat);
repeatButton.setOnClickListener(v -> presenter.toggleRepeat());
shuffleButton = (ImageButton) rootView.findViewById(R.id.shuffle);
shuffleButton.setOnClickListener(v -> presenter.toggleShuffle());
nextButton = (RepeatingImageButton) rootView.findViewById(R.id.next);
nextButton.setOnClickListener(v -> presenter.skip());
nextButton.setRepeatListener((v, duration, repeatcount) -> presenter.scanForward(repeatcount, duration));
prevButton = (RepeatingImageButton) rootView.findViewById(R.id.prev);
prevButton.setOnClickListener(v -> presenter.prev(true));
prevButton.setRepeatListener((v, duration, repeatcount) -> presenter.scanBackward(repeatcount, duration));
currentTime = (TextView) rootView.findViewById(R.id.current_time);
totalTime = (TextView) rootView.findViewById(R.id.total_time);
queuePosition = (TextView) rootView.findViewById(R.id.queue_position);
track = (TextView) rootView.findViewById(R.id.text1);
album = (TextView) rootView.findViewById(R.id.text2);
artist = (TextView) rootView.findViewById(R.id.text3);
textViewContainer = rootView.findViewById(R.id.textContainer);
buttonContainer = rootView.findViewById(R.id.button_container);
fab = (FloatingActionButton) rootView.findViewById(R.id.fab);
if (fab != null) {
fab.setOnClickListener(v -> {
if (fabIsAnimating) {
return;
}
toggleQueue();
});
}
seekBar = (SizableSeekBar) rootView.findViewById(R.id.seekbar);
seekBar.setMax(1000);
themeUIComponents();
//If the queueFragment exists in the child fragment manager, retrieve it
Fragment queueFragment = getChildFragmentManager().findFragmentByTag(QUEUE_FRAGMENT);
Fragment queuePagerFragment = getChildFragmentManager().findFragmentByTag(QUEUE_PAGER_FRAGMENT);
//We only want to add th
if (queueFragment == null && queuePagerFragment == null) {
getChildFragmentManager().beginTransaction()
.replace(R.id.main_container, QueuePagerFragment.newInstance(), QUEUE_PAGER_FRAGMENT)
.commit();
}
toggleFabVisibility(queueFragment == null, false);
return rootView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
presenter.bindView(this);
}
@Override
public void onDestroyView() {
super.onDestroyView();
presenter.unbindView(this);
}
public void update() {
if (presenter != null) {
presenter.updateTrackInfo();
}
}
public void themeUIComponents() {
if (nextButton != null) {
nextButton.setImageDrawable(DrawableUtils.getColoredStateListDrawableWithThemeColor(getActivity(), nextButton.getDrawable(), ThemeUtils.WHITE));
}
if (prevButton != null) {
prevButton.setImageDrawable(DrawableUtils.getColoredStateListDrawableWithThemeColor(getActivity(), prevButton.getDrawable(), ThemeUtils.WHITE));
}
if (seekBar != null) {
ThemeUtils.themeSeekBar(getActivity(), seekBar, true);
}
if (textViewContainer != null) {
textViewContainer.setBackgroundColor(ColorUtils.getPrimaryColorDark(getActivity()));
}
if (buttonContainer != null) {
buttonContainer.setBackgroundColor(ColorUtils.getPrimaryColor());
}
if (fab != null) {
fab.setBackgroundTintList(ColorStateList.valueOf(ColorUtils.getAccentColor()));
fab.setRippleColor(ColorUtils.darkerise(ColorUtils.getAccentColor(), 0.85f));
}
if (presenter != null) {
shuffleChanged(MusicUtils.getShuffleMode());
repeatChanged(MusicUtils.getRepeatMode());
}
}
@Override
public void onResume() {
super.onResume();
subscriptions = new CompositeSubscription();
Observable<SeekBarChangeEvent> sharedSeekBarEvents = RxSeekBar.changeEvents(seekBar)
.onBackpressureLatest()
.ofType(SeekBarChangeEvent.class)
.observeOn(AndroidSchedulers.mainThread())
.share();
subscriptions.add(sharedSeekBarEvents.subscribe(seekBarChangeEvent -> {
if (seekBarChangeEvent instanceof SeekBarStartChangeEvent) {
isSeeking = true;
} else if (seekBarChangeEvent instanceof SeekBarStopChangeEvent) {
isSeeking = false;
}
}));
subscriptions.add(sharedSeekBarEvents
.ofType(SeekBarProgressChangeEvent.class)
.filter(SeekBarProgressChangeEvent::fromUser)
.debounce(15, TimeUnit.MILLISECONDS)
.subscribe(seekBarChangeEvent -> presenter.seekTo(seekBarChangeEvent.progress())));
}
@Override
public void onPause() {
subscriptions.unsubscribe();
super.onPause();
}
@Override
public void onDestroy() {
sharedPreferences.unregisterOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener);
super.onDestroy();
}
public void toggleLyrics() {
Fragment fragment = getChildFragmentManager().findFragmentById(R.id.main_container);
if (fragment instanceof LyricsFragment) {
return;
}
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.abc_fade_in, R.anim.abc_fade_out);
if (fragment instanceof QueueFragment) {
ft.replace(R.id.main_container, new QueuePagerFragment(), QUEUE_PAGER_FRAGMENT);
toggleFabVisibility(true, true);
}
ft.add(R.id.main_container, new LyricsFragment(), LYRICS_FRAGMENT);
ft.commit();
}
public void toggleQueue() {
Fragment lyricsFragment = getChildFragmentManager().findFragmentByTag(LYRICS_FRAGMENT);
Fragment queueFragment = getChildFragmentManager().findFragmentByTag(QUEUE_FRAGMENT);
Fragment queuePagerFragment = getChildFragmentManager().findFragmentByTag(QUEUE_PAGER_FRAGMENT);
final FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out);
//Remove the lyrics fragment
if (lyricsFragment != null) {
fragmentTransaction.remove(lyricsFragment);
}
if (queueFragment != null) {
fragmentTransaction.remove(queueFragment);
fragmentTransaction.replace(R.id.main_container, new QueuePagerFragment(), QUEUE_PAGER_FRAGMENT);
toggleFabVisibility(true, true);
} else if (queuePagerFragment != null) {
fragmentTransaction.remove(queuePagerFragment);
fragmentTransaction.add(R.id.queue_container, QueueFragment.newInstance(), QUEUE_FRAGMENT);
bottomView.setClickable(true);
toggleFabVisibility(false, true);
}
fragmentTransaction.commitAllowingStateLoss();
}
private void toggleFabVisibility(boolean show, boolean animate) {
if (fab == null) {
return;
}
if (show && fab.getVisibility() == View.VISIBLE) {
return;
}
if (!show && fab.getVisibility() == View.GONE) {
return;
}
if (fabIsAnimating) {
return;
}
if (!animate) {
if (show) {
fab.setVisibility(View.VISIBLE);
} else {
fab.setVisibility(View.GONE);
}
return;
}
fabIsAnimating = true;
if (show) {
fab.setScaleX(0f);
fab.setScaleY(0f);
fab.setAlpha(0f);
fab.setVisibility(View.VISIBLE);
ObjectAnimator fadeAnimator = ObjectAnimator.ofFloat(fab, "alpha", 0f, 1f);
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(fab, "scaleX", 0f, 1f);
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(fab, "scaleY", 0f, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(fadeAnimator, scaleXAnimator, scaleYAnimator);
animatorSet.setDuration(350);
animatorSet.start();
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
fabIsAnimating = false;
}
});
} else {
ObjectAnimator fadeAnimator = ObjectAnimator.ofFloat(fab, "alpha", 1f, 0f);
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(fab, "scaleX", 1f, 0f);
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(fab, "scaleY", 1f, 0f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(fadeAnimator, scaleXAnimator, scaleYAnimator);
animatorSet.setDuration(250);
animatorSet.start();
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
fab.setVisibility(View.GONE);
fabIsAnimating = false;
}
});
}
}
public void setDragView(View view) {
dragView = view;
((MainActivity) getActivity()).setDragView(view, true);
}
public View getDragView() {
return dragView;
}
public boolean isQueueShowing() {
return getChildFragmentManager().findFragmentByTag(QUEUE_FRAGMENT) != null;
}
@Override
protected String screenName() {
return TAG;
}
////////////////////////////////////////////////////////////////////
// View implementation
////////////////////////////////////////////////////////////////////
@Override
public void setSeekProgress(int progress) {
if (!isSeeking) {
seekBar.setProgress(progress);
}
}
@Override
public void currentTimeVisibilityChanged(boolean visible) {
currentTime.setVisibility(visible ? View.VISIBLE : View.GONE);
}
@Override
public void currentTimeChanged(long seconds) {
currentTime.setText(StringUtils.makeTimeString(this.getActivity(), seconds));
}
@Override
public void queueChanged(int queuePosition, int queueLength) {
this.queuePosition.setText(String.format("%s / %s", queuePosition, queueLength));
}
@Override
public void playbackChanged(boolean isPlaying) {
if (isPlaying) {
if (playPauseView.isPlay()) {
playPauseView.toggle();
playPauseView.setContentDescription(getString(R.string.btn_pause));
}
} else {
if (!playPauseView.isPlay()) {
playPauseView.toggle();
playPauseView.setContentDescription(getString(R.string.btn_play));
}
}
}
@Override
public void shuffleChanged(@MusicService.ShuffleMode int shuffleMode) {
switch (MusicUtils.getShuffleMode()) {
case MusicService.ShuffleMode.OFF:
shuffleButton.setImageDrawable(DrawableUtils.getWhiteDrawable(getActivity(), R.drawable.ic_shuffle_white));
shuffleButton.setContentDescription(getString(R.string.btn_shuffle_off));
break;
case MusicService.ShuffleMode.ON:
shuffleButton.setImageDrawable(DrawableUtils.getColoredAccentDrawableNonWhite(getActivity(), getResources().getDrawable(R.drawable.ic_shuffle_white)));
shuffleButton.setContentDescription(getString(R.string.btn_shuffle_on));
break;
}
}
@Override
public void repeatChanged(@MusicService.RepeatMode int repeatMode) {
switch (MusicUtils.getRepeatMode()) {
case MusicService.RepeatMode.ALL:
repeatButton.setImageDrawable(DrawableUtils.getColoredAccentDrawableNonWhite(getActivity(), getResources().getDrawable(R.drawable.ic_repeat_white)));
repeatButton.setContentDescription(getResources().getString(R.string.btn_repeat_all));
break;
case MusicService.RepeatMode.ONE:
repeatButton.setImageDrawable(DrawableUtils.getColoredAccentDrawableNonWhite(getActivity(), getResources().getDrawable(R.drawable.ic_repeat_one_white)));
repeatButton.setContentDescription(getResources().getString(R.string.btn_repeat_current));
break;
case MusicService.RepeatMode.OFF:
repeatButton.setImageDrawable(DrawableUtils.getWhiteDrawable(getActivity(), R.drawable.ic_repeat_white));
repeatButton.setContentDescription(getResources().getString(R.string.btn_repeat_off));
break;
}
}
@Override
public void favoriteChanged() {
getActivity().supportInvalidateOptionsMenu();
}
@Override
public void trackInfoChanged(@Nullable Song song) {
if (song == null) return;
String totalTime = StringUtils.makeTimeString(this.getActivity(), song.duration / 1000);
if (!TextUtils.isEmpty(totalTime)) {
this.totalTime.setText(String.format(" / %s", totalTime));
}
track.setText(song.name);
track.setSelected(true);
album.setText(String.format("%s | %s", song.artistName, song.albumName));
}
}