summaryrefslogtreecommitdiff
path: root/app/src/main/java/de/danoeh/antennapod/fragment
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/de/danoeh/antennapod/fragment')
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java386
1 files changed, 380 insertions, 6 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
index 6b6b07d82..222daf059 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
@@ -1,37 +1,411 @@
package de.danoeh.antennapod.fragment;
+import android.content.Context;
+import android.content.SharedPreferences;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.SeekBar;
+import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+import androidx.viewpager.widget.ViewPager;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MediaplayerActivity;
+import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
+import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
+import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.playback.PlaybackService;
+import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.util.IntentUtils;
+import de.danoeh.antennapod.core.util.TimeSpeedConverter;
+import de.danoeh.antennapod.core.util.playback.Playable;
+import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.dialog.VariableSpeedDialog;
+import de.danoeh.antennapod.view.PagerIndicatorView;
+import de.danoeh.antennapod.view.PlaybackSpeedIndicatorView;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.text.DecimalFormat;
/**
* Shows the audio player.
*/
-public class AudioPlayerFragment extends Fragment {
+public class AudioPlayerFragment extends Fragment implements SeekBar.OnSeekBarChangeListener {
public static final String TAG = "AudioPlayerFragment";
+ private static final int POS_COVER = 0;
+ private static final int POS_DESCR = 1;
+ private static final int POS_CHAPTERS = 2;
+ private static final int NUM_CONTENT_FRAGMENTS = 3;
+ private static final String PREFS = "AudioPlayerFragmentPreferences";
+ private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft";
+ private static final float EPSILON = 0.001f;
+
+ PlaybackSpeedIndicatorView butPlaybackSpeed;
+ TextView txtvPlaybackSpeed;
+ private ViewPager pager;
+ private PagerIndicatorView pageIndicator;
+ private AudioPlayerPagerAdapter pagerAdapter;
+ private TextView txtvPosition;
+ private TextView txtvLength;
+ private SeekBar sbPosition;
+ private ImageButton butRev;
+ private TextView txtvRev;
+ private ImageButton butPlay;
+ private ImageButton butFF;
+ private TextView txtvFF;
+ private ImageButton butSkip;
+
+ private PlaybackController controller;
+ private boolean showTimeLeft;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.audioplayer_fragment, container, false);
- ((AppCompatActivity) getActivity()).setSupportActionBar(root.findViewById(R.id.toolbar));
+ Toolbar toolbar = root.findViewById(R.id.toolbar);
+ toolbar.setTitle("");
+ ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
+
+ butPlaybackSpeed = root.findViewById(R.id.butPlaybackSpeed);
+ txtvPlaybackSpeed = root.findViewById(R.id.txtvPlaybackSpeed);
+ sbPosition = root.findViewById(R.id.sbPosition);
+ txtvPosition = root.findViewById(R.id.txtvPosition);
+ txtvLength = root.findViewById(R.id.txtvLength);
+ butRev = root.findViewById(R.id.butRev);
+ txtvRev = root.findViewById(R.id.txtvRev);
+ butPlay = root.findViewById(R.id.butPlay);
+ butFF = root.findViewById(R.id.butFF);
+ txtvFF = root.findViewById(R.id.txtvFF);
+ butSkip = root.findViewById(R.id.butSkip);
+ setupLengthTextView();
+ setupControlButtons();
+ setupPlaybackSpeedButton();
+ txtvRev.setText(String.valueOf(UserPreferences.getRewindSecs()));
+ txtvFF.setText(String.valueOf(UserPreferences.getFastForwardSecs()));
+ sbPosition.setOnSeekBarChangeListener(this);
+ pager = root.findViewById(R.id.pager);
+ pagerAdapter = new AudioPlayerPagerAdapter(getFragmentManager());
+ pager.setAdapter(pagerAdapter);
+ pageIndicator = root.findViewById(R.id.page_indicator);
+ pageIndicator.setViewPager(pager);
+ pageIndicator.setOnClickListener(v ->
+ pager.setCurrentItem((pager.getCurrentItem() + 1) % pager.getChildCount()));
return root;
}
+ private void setupControlButtons() {
+ butRev.setOnClickListener(v -> {
+ if (controller != null) {
+ int curr = controller.getPosition();
+ controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
+ }
+ });
+ butRev.setOnLongClickListener(v -> {
+ //showSkipPreference(MediaplayerActivity.this, MediaplayerActivity.SkipDirection.SKIP_REWIND);
+ return true;
+ });
+ butPlay.setOnClickListener(v -> {
+ if (controller != null) {
+ controller.init();
+ controller.playPause();
+ }
+ });
+ butFF.setOnClickListener(v -> {
+ if (controller != null) {
+ int curr = controller.getPosition();
+ controller.seekTo(curr + UserPreferences.getFastForwardSecs() * 1000);
+ }
+ });
+ butFF.setOnLongClickListener(v -> {
+ //showSkipPreference(MediaplayerActivity.this, MediaplayerActivity.SkipDirection.SKIP_FORWARD);
+ return false;
+ });
+ butSkip.setOnClickListener(v ->
+ IntentUtils.sendLocalBroadcast(getActivity(), PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
+ }
+
+ private void setupLengthTextView() {
+ SharedPreferences prefs = getContext().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
+ showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false);
+ txtvLength.setOnClickListener(v -> {
+ if (controller == null) {
+ return;
+ }
+ showTimeLeft = !showTimeLeft;
+ prefs.edit().putBoolean(PREF_SHOW_TIME_LEFT, showTimeLeft).apply();
+ updatePosition(new PlaybackPositionEvent(controller.getPosition(), controller.getDuration()));
+ });
+ }
+
+ private void setupPlaybackSpeedButton() {
+ butPlaybackSpeed.setOnClickListener(v -> {
+ if (controller == null) {
+ return;
+ }
+ if (!controller.canSetPlaybackSpeed()) {
+ VariableSpeedDialog.showGetPluginDialog(getContext());
+ return;
+ }
+ float[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
+ float currentSpeed = controller.getCurrentPlaybackSpeedMultiplier();
+
+ int newSpeedIndex = 0;
+ while (newSpeedIndex < availableSpeeds.length && availableSpeeds[newSpeedIndex] < currentSpeed + EPSILON) {
+ newSpeedIndex++;
+ }
+
+ float newSpeed;
+ if (availableSpeeds.length == 0) {
+ newSpeed = 1.0f;
+ } else if (newSpeedIndex == availableSpeeds.length) {
+ newSpeed = availableSpeeds[0];
+ } else {
+ newSpeed = availableSpeeds[newSpeedIndex];
+ }
+
+ PlaybackPreferences.setCurrentlyPlayingTemporaryPlaybackSpeed(newSpeed);
+ UserPreferences.setPlaybackSpeed(newSpeed);
+ controller.setPlaybackSpeed(newSpeed);
+ updateUi();
+ });
+ butPlaybackSpeed.setOnLongClickListener(v -> {
+ VariableSpeedDialog.showDialog(getContext());
+ return true;
+ });
+ butPlaybackSpeed.setVisibility(View.VISIBLE);
+ txtvPlaybackSpeed.setVisibility(View.VISIBLE);
+ }
+
+ protected void updatePlaybackSpeedButton() {
+ if (butPlaybackSpeed == null || controller == null) {
+ return;
+ }
+ float speed = 1.0f;
+ if (controller.canSetPlaybackSpeed()) {
+ speed = PlaybackSpeedUtils.getCurrentPlaybackSpeed(controller.getMedia());
+ }
+ String speedStr = new DecimalFormat("0.00").format(speed);
+ txtvPlaybackSpeed.setText(speedStr);
+ butPlaybackSpeed.setSpeed(speed);
+ butPlaybackSpeed.setAlpha(controller.canSetPlaybackSpeed() ? 1.0f : 0.5f);
+ butPlaybackSpeed.setVisibility(View.VISIBLE);
+ txtvPlaybackSpeed.setVisibility(View.VISIBLE);
+ }
+
+ private PlaybackController newPlaybackController() {
+ return new PlaybackController(getActivity(), false) {
+
+ @Override
+ public void setupGUI() {
+ updateUi();
+ }
+
+ @Override
+ public void onBufferStart() {
+ //MediaplayerActivity.this.onBufferStart();
+ }
+
+ @Override
+ public void onBufferEnd() {
+ //MediaplayerActivity.this.onBufferEnd();
+ }
+
+ @Override
+ public void onBufferUpdate(float progress) {
+ //MediaplayerActivity.this.onBufferUpdate(progress);
+ }
+
+ @Override
+ public void handleError(int code) {
+ //MediaplayerActivity.this.handleError(code);
+ }
+
+ @Override
+ public void onReloadNotification(int code) {
+ //MediaplayerActivity.this.onReloadNotification(code);
+ }
+
+ @Override
+ public void onSleepTimerUpdate() {
+ getActivity().invalidateOptionsMenu();
+ }
+
+ @Override
+ public ImageButton getPlayButton() {
+ return butPlay;
+ }
+
+ @Override
+ public void postStatusMsg(int msg, boolean showToast) {
+ //MediaplayerActivity.this.postStatusMsg(msg, showToast);
+ }
+
+ @Override
+ public void clearStatusMsg() {
+ //MediaplayerActivity.this.clearStatusMsg();
+ }
+
+ @Override
+ public boolean loadMediaInfo() {
+ updateUi();
+ return true;
+ }/*
+
+ @Override
+ public void onServiceQueried() {
+ MediaplayerActivity.this.onServiceQueried();
+ }
+
+ @Override
+ public void onShutdownNotification() {
+ finish();
+ }
+
+ @Override
+ public void onPlaybackEnd() {
+ finish();
+ }*/
+
+ @Override
+ public void onPlaybackSpeedChange() {
+ updatePlaybackSpeedButton();
+ }
+
+ @Override
+ public void onSetSpeedAbilityChanged() {
+ updatePlaybackSpeedButton();
+ }
+ };
+ }
+
+ private void updateUi() {
+ if (controller == null) {
+ return;
+ }
+ updatePosition(new PlaybackPositionEvent(controller.getPosition(), controller.getDuration()));
+ updatePlaybackSpeedButton();
+ getActivity().invalidateOptionsMenu();
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
-
- // So, we certainly *don't* have an options menu,
- // but unless we say we do, old options menus sometimes
- // persist. mfietz thinks this causes the ActionBar to be invalidated
setHasOptionsMenu(true);
}
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ controller = newPlaybackController();
+ controller.init();
+ updateUi();
+ EventBus.getDefault().register(this);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ controller.release();
+ controller = null;
+ EventBus.getDefault().unregister(this);
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void updatePosition(PlaybackPositionEvent event) {
+ if (controller == null || txtvPosition == null || txtvLength == null || sbPosition == null) {
+ return;
+ }
+
+ TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
+ int currentPosition = converter.convert(event.getPosition());
+ int duration = converter.convert(event.getDuration());
+ int remainingTime = converter.convert(event.getDuration() - event.getPosition());
+ Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition));
+ if (currentPosition == PlaybackService.INVALID_TIME || duration == PlaybackService.INVALID_TIME) {
+ Log.w(TAG, "Could not react to position observer update because of invalid time");
+ return;
+ }
+ txtvPosition.setText(Converter.getDurationStringLong(currentPosition));
+ if (showTimeLeft) {
+ txtvLength.setText("-" + Converter.getDurationStringLong(remainingTime));
+ } else {
+ txtvLength.setText(Converter.getDurationStringLong(duration));
+ }
+ float progress = ((float) event.getPosition()) / event.getDuration();
+ sbPosition.setProgress((int) (progress * sbPosition.getMax()));
+ }
+
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (controller == null || txtvLength == null) {
+ return;
+ }
+ if (fromUser) {
+ float prog = progress / ((float) seekBar.getMax());
+ int duration = controller.getDuration();
+ TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
+ int position = converter.convert((int) (prog * duration));
+ txtvPosition.setText(Converter.getDurationStringLong(position));
+
+ if (showTimeLeft && prog != 0) {
+ int timeLeft = converter.convert(duration - (int) (prog * duration));
+ String length = "-" + Converter.getDurationStringLong(timeLeft);
+ txtvLength.setText(length);
+ }
+ }
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ // interrupt position Observer, restart later
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ if (controller != null) {
+ float prog = seekBar.getProgress() / ((float) seekBar.getMax());
+ controller.seekTo((int) (prog * controller.getDuration()));
+ }
+ }
+
+ private static class AudioPlayerPagerAdapter extends FragmentStatePagerAdapter {
+ private static final String TAG = "AudioPlayerPagerAdapter";
+
+ public AudioPlayerPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ Log.d(TAG, "getItem(" + position + ")");
+ switch (position) {
+ case POS_COVER:
+ return new CoverFragment();
+ case POS_DESCR:
+ return new ItemDescriptionFragment();
+ case POS_CHAPTERS:
+ return new ChaptersFragment();
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return NUM_CONTENT_FRAGMENTS;
+ }
+ }
}