Moved all code from MediaPlayerActivity to VideoPlayerActivity
This commit is contained in:
parent
362e66cf08
commit
c3d7209f09
|
@ -1,633 +0,0 @@
|
|||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.SeekBar.OnSeekBarChangeListener;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import de.danoeh.antennapod.core.event.ServiceEvent;
|
||||
import de.danoeh.antennapod.view.PlayButton;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.core.app.ActivityOptionsCompat;
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.ShareUtils;
|
||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||
import de.danoeh.antennapod.core.util.TimeSpeedConverter;
|
||||
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
|
||||
import de.danoeh.antennapod.core.util.playback.MediaPlayerError;
|
||||
import de.danoeh.antennapod.model.playback.Playable;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
||||
import de.danoeh.antennapod.dialog.PlaybackControlsDialog;
|
||||
import de.danoeh.antennapod.dialog.ShareDialog;
|
||||
import de.danoeh.antennapod.dialog.SkipPreferenceDialog;
|
||||
import de.danoeh.antennapod.dialog.SleepTimerDialog;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Provides general features which are both needed for playing audio and video
|
||||
* files.
|
||||
*/
|
||||
public abstract class MediaplayerActivity extends CastEnabledActivity implements OnSeekBarChangeListener {
|
||||
private static final String TAG = "MediaplayerActivity";
|
||||
|
||||
PlaybackController controller;
|
||||
|
||||
private TextView txtvPosition;
|
||||
private TextView txtvLength;
|
||||
SeekBar sbPosition;
|
||||
private ImageButton butRev;
|
||||
private TextView txtvRev;
|
||||
private PlayButton butPlay;
|
||||
private ImageButton butFF;
|
||||
private TextView txtvFF;
|
||||
private ImageButton butSkip;
|
||||
private CardView cardViewSeek;
|
||||
private TextView txtvSeek;
|
||||
|
||||
private boolean showTimeLeft = false;
|
||||
|
||||
private boolean isFavorite = false;
|
||||
|
||||
private Disposable disposable;
|
||||
|
||||
private PlaybackController newPlaybackController() {
|
||||
return new PlaybackController(this) {
|
||||
@Override
|
||||
public void onPositionObserverUpdate() {
|
||||
MediaplayerActivity.this.onPositionObserverUpdate();
|
||||
}
|
||||
|
||||
@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() {
|
||||
supportInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updatePlayButtonShowsPlay(boolean showPlay) {
|
||||
butPlay.setIsShowPlay(showPlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMediaInfo() {
|
||||
MediaplayerActivity.this.loadMediaInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAwaitingVideoSurface() {
|
||||
MediaplayerActivity.this.onAwaitingVideoSurface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackEnd() {
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setScreenOn(boolean enable) {
|
||||
super.setScreenOn(enable);
|
||||
MediaplayerActivity.this.setScreenOn(enable);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(PlaybackPositionEvent event) {
|
||||
onPositionObserverUpdate();
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onPlaybackServiceChanged(ServiceEvent event) {
|
||||
if (event.action == ServiceEvent.Action.SERVICE_SHUT_DOWN) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
void setScreenOn(boolean enable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(R.style.Theme_AntennaPod_VideoPlayer);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Log.d(TAG, "onCreate()");
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
|
||||
getWindow().setFormat(PixelFormat.TRANSPARENT);
|
||||
setupGUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
|
||||
if (controller != null) {
|
||||
controller.reinitServiceIfPaused();
|
||||
controller.pause();
|
||||
}
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be used to switch to another player activity if the mime type is
|
||||
* not the correct one for the current activity.
|
||||
*/
|
||||
protected abstract void onReloadNotification(int notificationCode);
|
||||
|
||||
/**
|
||||
* Should be used to inform the user that the PlaybackService is currently
|
||||
* buffering.
|
||||
*/
|
||||
protected void onBufferStart() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be used to hide the view that was showing the 'buffering'-message.
|
||||
*/
|
||||
protected void onBufferEnd() {
|
||||
|
||||
}
|
||||
|
||||
private void onBufferUpdate(float progress) {
|
||||
if (sbPosition != null) {
|
||||
sbPosition.setSecondaryProgress((int) (progress * sbPosition.getMax()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
controller = newPlaybackController();
|
||||
controller.init();
|
||||
loadMediaInfo();
|
||||
onPositionObserverUpdate();
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
Log.d(TAG, "onStop()");
|
||||
if (controller != null) {
|
||||
controller.release();
|
||||
controller = null; // prevent leak
|
||||
}
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
EventBus.getDefault().unregister(this);
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
super.onTrimMemory(level);
|
||||
Glide.get(this).trimMemory(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
Glide.get(this).clearMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
requestCastButton(menu);
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.mediaplayer, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Playable media = controller.getMedia();
|
||||
boolean isFeedMedia = (media instanceof FeedMedia);
|
||||
|
||||
menu.findItem(R.id.open_feed_item).setVisible(isFeedMedia); // FeedMedia implies it belongs to a Feed
|
||||
|
||||
boolean hasWebsiteLink = ( getWebsiteLinkWithFallback(media) != null );
|
||||
menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink);
|
||||
|
||||
boolean isItemAndHasLink = isFeedMedia &&
|
||||
ShareUtils.hasLinkToShare(((FeedMedia) media).getItem());
|
||||
|
||||
boolean isItemHasDownloadLink = isFeedMedia && ((FeedMedia) media).getDownload_url() != null;
|
||||
|
||||
menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink);
|
||||
|
||||
menu.findItem(R.id.add_to_favorites_item).setVisible(false);
|
||||
menu.findItem(R.id.remove_from_favorites_item).setVisible(false);
|
||||
if (isFeedMedia) {
|
||||
menu.findItem(R.id.add_to_favorites_item).setVisible(!isFavorite);
|
||||
menu.findItem(R.id.remove_from_favorites_item).setVisible(isFavorite);
|
||||
}
|
||||
|
||||
menu.findItem(R.id.set_sleeptimer_item).setVisible(!controller.sleepTimerActive());
|
||||
menu.findItem(R.id.disable_sleeptimer_item).setVisible(controller.sleepTimerActive());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Playable media = controller.getMedia();
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
Intent intent = new Intent(MediaplayerActivity.this,
|
||||
MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
| Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
View cover = findViewById(R.id.imgvCover);
|
||||
if (cover != null) {
|
||||
ActivityOptionsCompat options = ActivityOptionsCompat
|
||||
.makeSceneTransitionAnimation(MediaplayerActivity.this, cover, "coverTransition");
|
||||
startActivity(intent, options.toBundle());
|
||||
} else {
|
||||
startActivity(intent);
|
||||
}
|
||||
finish();
|
||||
return true;
|
||||
} else {
|
||||
if (media != null) {
|
||||
final @Nullable FeedItem feedItem = getFeedItem(media); // some options option requires FeedItem
|
||||
switch (item.getItemId()) {
|
||||
case R.id.add_to_favorites_item:
|
||||
if (feedItem != null) {
|
||||
DBWriter.addFavoriteItem(feedItem);
|
||||
isFavorite = true;
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
break;
|
||||
case R.id.remove_from_favorites_item:
|
||||
if (feedItem != null) {
|
||||
DBWriter.removeFavoriteItem(feedItem);
|
||||
isFavorite = false;
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
break;
|
||||
case R.id.disable_sleeptimer_item: // Fall-through
|
||||
case R.id.set_sleeptimer_item:
|
||||
new SleepTimerDialog().show(getSupportFragmentManager(), "SleepTimerDialog");
|
||||
break;
|
||||
case R.id.audio_controls:
|
||||
PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance();
|
||||
dialog.show(getSupportFragmentManager(), "playback_controls");
|
||||
break;
|
||||
case R.id.open_feed_item:
|
||||
if (feedItem != null) {
|
||||
Intent intent = MainActivity.getIntentToOpenFeed(this, feedItem.getFeedId());
|
||||
startActivity(intent);
|
||||
}
|
||||
break;
|
||||
case R.id.visit_website_item:
|
||||
IntentUtils.openInBrowser(MediaplayerActivity.this, getWebsiteLinkWithFallback(media));
|
||||
break;
|
||||
case R.id.share_item:
|
||||
if (feedItem != null) {
|
||||
ShareDialog shareDialog = ShareDialog.newInstance(feedItem);
|
||||
shareDialog.show(getSupportFragmentManager(), "ShareEpisodeDialog");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getWebsiteLinkWithFallback(Playable media) {
|
||||
if (media == null) {
|
||||
return null;
|
||||
} else if (StringUtils.isNotBlank(media.getWebsiteLink())) {
|
||||
return media.getWebsiteLink();
|
||||
} else if (media instanceof FeedMedia) {
|
||||
return FeedItemUtil.getLinkWithFallback(((FeedMedia)media).getItem());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
Log.d(TAG, "onResume()");
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by 'handleStatus()' when the PlaybackService is waiting for
|
||||
* a video surface.
|
||||
*/
|
||||
protected abstract void onAwaitingVideoSurface();
|
||||
|
||||
void onPositionObserverUpdate() {
|
||||
if (controller == null || txtvPosition == null || txtvLength == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
|
||||
int currentPosition = converter.convert(controller.getPosition());
|
||||
int duration = converter.convert(controller.getDuration());
|
||||
int remainingTime = converter.convert(
|
||||
controller.getDuration() - controller.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));
|
||||
}
|
||||
updateProgressbarPosition(currentPosition, duration);
|
||||
}
|
||||
|
||||
private void updateProgressbarPosition(int position, int duration) {
|
||||
Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration + ")");
|
||||
if(sbPosition == null) {
|
||||
return;
|
||||
}
|
||||
float progress = ((float) position) / duration;
|
||||
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load information about the media that is going to be played or currently
|
||||
* being played. This method will be called when the activity is connected
|
||||
* to the PlaybackService to ensure that the activity has the right
|
||||
* FeedMedia object.
|
||||
*/
|
||||
void loadMediaInfo() {
|
||||
Log.d(TAG, "loadMediaInfo()");
|
||||
if (controller == null || controller.getMedia() == null) {
|
||||
return;
|
||||
}
|
||||
showTimeLeft = UserPreferences.shouldShowRemainingTime();
|
||||
onPositionObserverUpdate();
|
||||
checkFavorite();
|
||||
}
|
||||
|
||||
void setupGUI() {
|
||||
setContentView(R.layout.videoplayer_activity);
|
||||
sbPosition = findViewById(R.id.sbPosition);
|
||||
txtvPosition = findViewById(R.id.txtvPosition);
|
||||
cardViewSeek = findViewById(R.id.cardViewSeek);
|
||||
txtvSeek = findViewById(R.id.txtvSeek);
|
||||
|
||||
showTimeLeft = UserPreferences.shouldShowRemainingTime();
|
||||
Log.d("timeleft", showTimeLeft ? "true" : "false");
|
||||
txtvLength = findViewById(R.id.txtvLength);
|
||||
if (txtvLength != null) {
|
||||
txtvLength.setOnClickListener(v -> {
|
||||
showTimeLeft = !showTimeLeft;
|
||||
Playable media = controller.getMedia();
|
||||
if (media == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
|
||||
String length;
|
||||
if (showTimeLeft) {
|
||||
int remainingTime = converter.convert(
|
||||
media.getDuration() - media.getPosition());
|
||||
|
||||
length = "-" + Converter.getDurationStringLong(remainingTime);
|
||||
} else {
|
||||
int duration = converter.convert(media.getDuration());
|
||||
length = Converter.getDurationStringLong(duration);
|
||||
}
|
||||
txtvLength.setText(length);
|
||||
|
||||
UserPreferences.setShowRemainTimeSetting(showTimeLeft);
|
||||
Log.d("timeleft on click", showTimeLeft ? "true" : "false");
|
||||
});
|
||||
}
|
||||
|
||||
butRev = findViewById(R.id.butRev);
|
||||
txtvRev = findViewById(R.id.txtvRev);
|
||||
if (txtvRev != null) {
|
||||
txtvRev.setText(NumberFormat.getInstance().format(UserPreferences.getRewindSecs()));
|
||||
}
|
||||
butPlay = findViewById(R.id.butPlay);
|
||||
butPlay.setIsVideoScreen(true);
|
||||
butFF = findViewById(R.id.butFF);
|
||||
txtvFF = findViewById(R.id.txtvFF);
|
||||
if (txtvFF != null) {
|
||||
txtvFF.setText(NumberFormat.getInstance().format(UserPreferences.getFastForwardSecs()));
|
||||
}
|
||||
butSkip = findViewById(R.id.butSkip);
|
||||
|
||||
// SEEKBAR SETUP
|
||||
|
||||
sbPosition.setOnSeekBarChangeListener(this);
|
||||
|
||||
// BUTTON SETUP
|
||||
|
||||
if (butRev != null) {
|
||||
butRev.setOnClickListener(v -> onRewind());
|
||||
butRev.setOnLongClickListener(v -> {
|
||||
SkipPreferenceDialog.showSkipPreference(MediaplayerActivity.this,
|
||||
SkipPreferenceDialog.SkipDirection.SKIP_REWIND, txtvRev);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
butPlay.setOnClickListener(v -> onPlayPause());
|
||||
|
||||
if (butFF != null) {
|
||||
butFF.setOnClickListener(v -> onFastForward());
|
||||
butFF.setOnLongClickListener(v -> {
|
||||
SkipPreferenceDialog.showSkipPreference(MediaplayerActivity.this,
|
||||
SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, txtvFF);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (butSkip != null) {
|
||||
butSkip.setOnClickListener(v ->
|
||||
IntentUtils.sendLocalBroadcast(MediaplayerActivity.this, PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
|
||||
}
|
||||
}
|
||||
|
||||
void onRewind() {
|
||||
if (controller == null) {
|
||||
return;
|
||||
}
|
||||
int curr = controller.getPosition();
|
||||
controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
|
||||
}
|
||||
|
||||
void onPlayPause() {
|
||||
if(controller == null) {
|
||||
return;
|
||||
}
|
||||
controller.init();
|
||||
controller.playPause();
|
||||
}
|
||||
|
||||
void onFastForward() {
|
||||
if (controller == null) {
|
||||
return;
|
||||
}
|
||||
int curr = controller.getPosition();
|
||||
controller.seekTo(curr + UserPreferences.getFastForwardSecs() * 1000);
|
||||
}
|
||||
|
||||
private void handleError(int errorCode) {
|
||||
final AlertDialog.Builder errorDialog = new AlertDialog.Builder(this);
|
||||
errorDialog.setTitle(R.string.error_label);
|
||||
errorDialog.setMessage(MediaPlayerError.getErrorString(this, errorCode));
|
||||
errorDialog.setNeutralButton("OK",
|
||||
(dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
}
|
||||
);
|
||||
errorDialog.create().show();
|
||||
}
|
||||
|
||||
private float prog;
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (controller == null || txtvLength == null) {
|
||||
return;
|
||||
}
|
||||
if (fromUser) {
|
||||
prog = progress / ((float) seekBar.getMax());
|
||||
TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
|
||||
int position = converter.convert((int) (prog * controller.getDuration()));
|
||||
txtvSeek.setText(Converter.getDurationStringLong(position));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
cardViewSeek.setScaleX(.8f);
|
||||
cardViewSeek.setScaleY(.8f);
|
||||
cardViewSeek.animate()
|
||||
.setInterpolator(new FastOutSlowInInterpolator())
|
||||
.alpha(1f).scaleX(1f).scaleY(1f)
|
||||
.setDuration(200)
|
||||
.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
if (controller != null) {
|
||||
controller.seekTo((int) (prog * controller.getDuration()));
|
||||
}
|
||||
cardViewSeek.setScaleX(1f);
|
||||
cardViewSeek.setScaleY(1f);
|
||||
cardViewSeek.animate()
|
||||
.setInterpolator(new FastOutSlowInInterpolator())
|
||||
.alpha(0f).scaleX(.8f).scaleY(.8f)
|
||||
.setDuration(200)
|
||||
.start();
|
||||
}
|
||||
|
||||
private void checkFavorite() {
|
||||
FeedItem feedItem = getFeedItem(controller.getMedia());
|
||||
if (feedItem == null) {
|
||||
return;
|
||||
}
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
disposable = Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId()))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
item -> {
|
||||
boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
|
||||
if (isFavorite != isFav) {
|
||||
isFavorite = isFav;
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static FeedItem getFeedItem(@Nullable Playable playable) {
|
||||
if (playable instanceof FeedMedia) {
|
||||
return ((FeedMedia) playable).getItem();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
|
@ -9,12 +11,19 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.animation.AlphaAnimation;
|
||||
import android.view.animation.AnimationSet;
|
||||
import android.view.animation.ScaleAnimation;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.core.app.ActivityOptionsCompat;
|
||||
import androidx.core.view.WindowCompat;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import android.util.Log;
|
||||
|
@ -33,21 +42,51 @@ import android.widget.ProgressBar;
|
|||
import android.widget.SeekBar;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
|
||||
import com.bumptech.glide.Glide;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
import de.danoeh.antennapod.core.event.ServiceEvent;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.ShareUtils;
|
||||
import de.danoeh.antennapod.core.util.StorageUtils;
|
||||
import de.danoeh.antennapod.core.util.TimeSpeedConverter;
|
||||
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
|
||||
import de.danoeh.antennapod.core.util.playback.MediaPlayerError;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
||||
import de.danoeh.antennapod.dialog.PlaybackControlsDialog;
|
||||
import de.danoeh.antennapod.dialog.ShareDialog;
|
||||
import de.danoeh.antennapod.dialog.SkipPreferenceDialog;
|
||||
import de.danoeh.antennapod.dialog.SleepTimerDialog;
|
||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.model.playback.Playable;
|
||||
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
|
||||
import de.danoeh.antennapod.view.AspectRatioVideoView;
|
||||
import de.danoeh.antennapod.view.PlayButton;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
/**
|
||||
* Activity for playing video files.
|
||||
*/
|
||||
public class VideoplayerActivity extends MediaplayerActivity {
|
||||
public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.OnSeekBarChangeListener {
|
||||
private static final String TAG = "VideoplayerActivity";
|
||||
|
||||
/**
|
||||
|
@ -68,6 +107,23 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
private ProgressBar progressIndicator;
|
||||
private FrameLayout videoframe;
|
||||
private ImageView skipAnimationView;
|
||||
private TextView txtvPosition;
|
||||
private TextView txtvLength;
|
||||
private SeekBar sbPosition;
|
||||
private ImageButton butRev;
|
||||
private TextView txtvRev;
|
||||
private PlayButton butPlay;
|
||||
private ImageButton butFF;
|
||||
private TextView txtvFF;
|
||||
private ImageButton butSkip;
|
||||
private CardView cardViewSeek;
|
||||
private TextView txtvSeek;
|
||||
|
||||
private PlaybackController controller;
|
||||
private boolean showTimeLeft = false;
|
||||
private boolean isFavorite = false;
|
||||
private Disposable disposable;
|
||||
private float prog;
|
||||
|
||||
@SuppressLint("AppCompatMethod")
|
||||
@Override
|
||||
|
@ -75,13 +131,21 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
|
||||
supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY); // has to be called before setting layout content
|
||||
setTheme(R.style.Theme_AntennaPod_VideoPlayer);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Log.d(TAG, "onCreate()");
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
|
||||
getWindow().setFormat(PixelFormat.TRANSPARENT);
|
||||
setupGUI();
|
||||
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(0x80000000));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
if (PlaybackService.isCasting()) {
|
||||
Intent intent = PlaybackService.getPlayerActivityIntent(this);
|
||||
if (!intent.getComponent().getClassName().equals(VideoplayerActivity.class.getName())) {
|
||||
|
@ -94,6 +158,14 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
if (controller != null) {
|
||||
controller.release();
|
||||
controller = null; // prevent leak
|
||||
}
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
EventBus.getDefault().unregister(this);
|
||||
super.onStop();
|
||||
if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
|
||||
videoControlsHider.stop();
|
||||
|
@ -109,6 +181,16 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
controller = newPlaybackController();
|
||||
controller.init();
|
||||
loadMediaInfo();
|
||||
onPositionObserverUpdate();
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
|
||||
|
@ -126,9 +208,94 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
super.onDestroy();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
super.onTrimMemory(level);
|
||||
Glide.get(this).trimMemory(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
Glide.get(this).clearMemory();
|
||||
}
|
||||
|
||||
private PlaybackController newPlaybackController() {
|
||||
return new PlaybackController(this) {
|
||||
@Override
|
||||
public void onPositionObserverUpdate() {
|
||||
VideoplayerActivity.this.onPositionObserverUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBufferStart() {
|
||||
VideoplayerActivity.this.onBufferStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBufferEnd() {
|
||||
VideoplayerActivity.this.onBufferEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBufferUpdate(float progress) {
|
||||
if (sbPosition != null) {
|
||||
sbPosition.setSecondaryProgress((int) (progress * sbPosition.getMax()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleError(int code) {
|
||||
VideoplayerActivity.this.handleError(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReloadNotification(int code) {
|
||||
VideoplayerActivity.this.onReloadNotification(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSleepTimerUpdate() {
|
||||
supportInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updatePlayButtonShowsPlay(boolean showPlay) {
|
||||
butPlay.setIsShowPlay(showPlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMediaInfo() {
|
||||
VideoplayerActivity.this.loadMediaInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAwaitingVideoSurface() {
|
||||
VideoplayerActivity.this.onAwaitingVideoSurface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackEnd() {
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setScreenOn(boolean enable) {
|
||||
super.setScreenOn(enable);
|
||||
VideoplayerActivity.this.setScreenOn(enable);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected void loadMediaInfo() {
|
||||
super.loadMediaInfo();
|
||||
Log.d(TAG, "loadMediaInfo()");
|
||||
if (controller == null || controller.getMedia() == null) {
|
||||
return;
|
||||
}
|
||||
showTimeLeft = UserPreferences.shouldShowRemainingTime();
|
||||
onPositionObserverUpdate();
|
||||
checkFavorite();
|
||||
Playable media = controller.getMedia();
|
||||
if (media != null) {
|
||||
getSupportActionBar().setSubtitle(media.getEpisodeTitle());
|
||||
|
@ -136,12 +303,90 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupGUI() {
|
||||
if (isSetup.getAndSet(true)) {
|
||||
return;
|
||||
}
|
||||
super.setupGUI();
|
||||
setContentView(R.layout.videoplayer_activity);
|
||||
sbPosition = findViewById(R.id.sbPosition);
|
||||
txtvPosition = findViewById(R.id.txtvPosition);
|
||||
cardViewSeek = findViewById(R.id.cardViewSeek);
|
||||
txtvSeek = findViewById(R.id.txtvSeek);
|
||||
|
||||
showTimeLeft = UserPreferences.shouldShowRemainingTime();
|
||||
Log.d("timeleft", showTimeLeft ? "true" : "false");
|
||||
txtvLength = findViewById(R.id.txtvLength);
|
||||
if (txtvLength != null) {
|
||||
txtvLength.setOnClickListener(v -> {
|
||||
showTimeLeft = !showTimeLeft;
|
||||
Playable media = controller.getMedia();
|
||||
if (media == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
|
||||
String length;
|
||||
if (showTimeLeft) {
|
||||
int remainingTime = converter.convert(
|
||||
media.getDuration() - media.getPosition());
|
||||
|
||||
length = "-" + Converter.getDurationStringLong(remainingTime);
|
||||
} else {
|
||||
int duration = converter.convert(media.getDuration());
|
||||
length = Converter.getDurationStringLong(duration);
|
||||
}
|
||||
txtvLength.setText(length);
|
||||
|
||||
UserPreferences.setShowRemainTimeSetting(showTimeLeft);
|
||||
Log.d("timeleft on click", showTimeLeft ? "true" : "false");
|
||||
});
|
||||
}
|
||||
|
||||
butRev = findViewById(R.id.butRev);
|
||||
txtvRev = findViewById(R.id.txtvRev);
|
||||
if (txtvRev != null) {
|
||||
txtvRev.setText(NumberFormat.getInstance().format(UserPreferences.getRewindSecs()));
|
||||
}
|
||||
butPlay = findViewById(R.id.butPlay);
|
||||
butPlay.setIsVideoScreen(true);
|
||||
butFF = findViewById(R.id.butFF);
|
||||
txtvFF = findViewById(R.id.txtvFF);
|
||||
if (txtvFF != null) {
|
||||
txtvFF.setText(NumberFormat.getInstance().format(UserPreferences.getFastForwardSecs()));
|
||||
}
|
||||
butSkip = findViewById(R.id.butSkip);
|
||||
|
||||
// SEEKBAR SETUP
|
||||
|
||||
sbPosition.setOnSeekBarChangeListener(this);
|
||||
|
||||
// BUTTON SETUP
|
||||
|
||||
if (butRev != null) {
|
||||
butRev.setOnClickListener(v -> onRewind());
|
||||
butRev.setOnLongClickListener(v -> {
|
||||
SkipPreferenceDialog.showSkipPreference(VideoplayerActivity.this,
|
||||
SkipPreferenceDialog.SkipDirection.SKIP_REWIND, txtvRev);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
butPlay.setOnClickListener(v -> onPlayPause());
|
||||
|
||||
if (butFF != null) {
|
||||
butFF.setOnClickListener(v -> onFastForward());
|
||||
butFF.setOnLongClickListener(v -> {
|
||||
SkipPreferenceDialog.showSkipPreference(VideoplayerActivity.this,
|
||||
SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, txtvFF);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (butSkip != null) {
|
||||
butSkip.setOnClickListener(v ->
|
||||
IntentUtils.sendLocalBroadcast(VideoplayerActivity.this, PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
|
||||
}
|
||||
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
controls = findViewById(R.id.controls);
|
||||
videoOverlay = findViewById(R.id.overlay);
|
||||
|
@ -163,7 +408,6 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
videoview.setAvailableSize(videoframe.getWidth(), videoframe.getHeight()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAwaitingVideoSurface() {
|
||||
setupVideoAspectRatio();
|
||||
if (videoSurfaceCreated && controller != null) {
|
||||
|
@ -273,24 +517,45 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
videoControlsShowing = !videoControlsShowing;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRewind() {
|
||||
super.onRewind();
|
||||
void onRewind() {
|
||||
if (controller == null) {
|
||||
return;
|
||||
}
|
||||
int curr = controller.getPosition();
|
||||
controller.seekTo(curr - UserPreferences.getRewindSecs() * 1000);
|
||||
setupVideoControlsToggler();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPlayPause() {
|
||||
super.onPlayPause();
|
||||
void onPlayPause() {
|
||||
if(controller == null) {
|
||||
return;
|
||||
}
|
||||
controller.init();
|
||||
controller.playPause();
|
||||
setupVideoControlsToggler();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFastForward() {
|
||||
super.onFastForward();
|
||||
void onFastForward() {
|
||||
if (controller == null) {
|
||||
return;
|
||||
}
|
||||
int curr = controller.getPosition();
|
||||
controller.seekTo(curr + UserPreferences.getFastForwardSecs() * 1000);
|
||||
setupVideoControlsToggler();
|
||||
}
|
||||
|
||||
private void handleError(int errorCode) {
|
||||
final AlertDialog.Builder errorDialog = new AlertDialog.Builder(this);
|
||||
errorDialog.setTitle(R.string.error_label);
|
||||
errorDialog.setMessage(MediaPlayerError.getErrorString(this, errorCode));
|
||||
errorDialog.setNeutralButton("OK",
|
||||
(dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
}
|
||||
);
|
||||
errorDialog.create().show();
|
||||
}
|
||||
|
||||
private final SurfaceHolder.Callback surfaceHolderCallback = new SurfaceHolder.Callback() {
|
||||
@Override
|
||||
|
@ -321,8 +586,6 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
protected void onReloadNotification(int notificationCode) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && PictureInPictureUtil.isInPictureInPictureMode(this)) {
|
||||
if (notificationCode == PlaybackService.EXTRA_CODE_AUDIO
|
||||
|
@ -339,24 +602,10 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
super.onStartTrackingTouch(seekBar);
|
||||
videoControlsHider.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
super.onStopTrackingTouch(seekBar);
|
||||
setupVideoControlsToggler();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBufferStart() {
|
||||
progressIndicator.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBufferEnd() {
|
||||
progressIndicator.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
@ -395,9 +644,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
hideVideoControls(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setScreenOn(boolean enable) {
|
||||
super.setScreenOn(enable);
|
||||
private void setScreenOn(boolean enable) {
|
||||
if (enable) {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
} else {
|
||||
|
@ -405,9 +652,58 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(PlaybackPositionEvent event) {
|
||||
onPositionObserverUpdate();
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onPlaybackServiceChanged(ServiceEvent event) {
|
||||
if (event.action == ServiceEvent.Action.SERVICE_SHUT_DOWN) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
requestCastButton(menu);
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.mediaplayer, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Playable media = controller.getMedia();
|
||||
boolean isFeedMedia = (media instanceof FeedMedia);
|
||||
|
||||
menu.findItem(R.id.open_feed_item).setVisible(isFeedMedia); // FeedMedia implies it belongs to a Feed
|
||||
|
||||
boolean hasWebsiteLink = ( getWebsiteLinkWithFallback(media) != null );
|
||||
menu.findItem(R.id.visit_website_item).setVisible(hasWebsiteLink);
|
||||
|
||||
boolean isItemAndHasLink = isFeedMedia &&
|
||||
ShareUtils.hasLinkToShare(((FeedMedia) media).getItem());
|
||||
|
||||
boolean isItemHasDownloadLink = isFeedMedia && ((FeedMedia) media).getDownload_url() != null;
|
||||
|
||||
menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink);
|
||||
|
||||
menu.findItem(R.id.add_to_favorites_item).setVisible(false);
|
||||
menu.findItem(R.id.remove_from_favorites_item).setVisible(false);
|
||||
if (isFeedMedia) {
|
||||
menu.findItem(R.id.add_to_favorites_item).setVisible(!isFavorite);
|
||||
menu.findItem(R.id.remove_from_favorites_item).setVisible(isFavorite);
|
||||
}
|
||||
|
||||
menu.findItem(R.id.set_sleeptimer_item).setVisible(!controller.sleepTimerActive());
|
||||
menu.findItem(R.id.disable_sleeptimer_item).setVisible(controller.sleepTimerActive());
|
||||
|
||||
if (PictureInPictureUtil.supportsPictureInPicture(this)) {
|
||||
menu.findItem(R.id.player_go_to_picture_in_picture).setVisible(true);
|
||||
}
|
||||
|
@ -421,7 +717,190 @@ public class VideoplayerActivity extends MediaplayerActivity {
|
|||
compatEnterPictureInPicture();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Playable media = controller.getMedia();
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
Intent intent = new Intent(VideoplayerActivity.this,
|
||||
MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
| Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
View cover = findViewById(R.id.imgvCover);
|
||||
if (cover != null) {
|
||||
ActivityOptionsCompat options = ActivityOptionsCompat
|
||||
.makeSceneTransitionAnimation(VideoplayerActivity.this, cover, "coverTransition");
|
||||
startActivity(intent, options.toBundle());
|
||||
} else {
|
||||
startActivity(intent);
|
||||
}
|
||||
finish();
|
||||
return true;
|
||||
} else {
|
||||
if (media != null) {
|
||||
final @Nullable FeedItem feedItem = getFeedItem(media); // some options option requires FeedItem
|
||||
switch (item.getItemId()) {
|
||||
case R.id.add_to_favorites_item:
|
||||
if (feedItem != null) {
|
||||
DBWriter.addFavoriteItem(feedItem);
|
||||
isFavorite = true;
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
break;
|
||||
case R.id.remove_from_favorites_item:
|
||||
if (feedItem != null) {
|
||||
DBWriter.removeFavoriteItem(feedItem);
|
||||
isFavorite = false;
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
break;
|
||||
case R.id.disable_sleeptimer_item: // Fall-through
|
||||
case R.id.set_sleeptimer_item:
|
||||
new SleepTimerDialog().show(getSupportFragmentManager(), "SleepTimerDialog");
|
||||
break;
|
||||
case R.id.audio_controls:
|
||||
PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance();
|
||||
dialog.show(getSupportFragmentManager(), "playback_controls");
|
||||
break;
|
||||
case R.id.open_feed_item:
|
||||
if (feedItem != null) {
|
||||
Intent intent = MainActivity.getIntentToOpenFeed(this, feedItem.getFeedId());
|
||||
startActivity(intent);
|
||||
}
|
||||
break;
|
||||
case R.id.visit_website_item:
|
||||
IntentUtils.openInBrowser(VideoplayerActivity.this, getWebsiteLinkWithFallback(media));
|
||||
break;
|
||||
case R.id.share_item:
|
||||
if (feedItem != null) {
|
||||
ShareDialog shareDialog = ShareDialog.newInstance(feedItem);
|
||||
shareDialog.show(getSupportFragmentManager(), "ShareEpisodeDialog");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getWebsiteLinkWithFallback(Playable media) {
|
||||
if (media == null) {
|
||||
return null;
|
||||
} else if (StringUtils.isNotBlank(media.getWebsiteLink())) {
|
||||
return media.getWebsiteLink();
|
||||
} else if (media instanceof FeedMedia) {
|
||||
return FeedItemUtil.getLinkWithFallback(((FeedMedia)media).getItem());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void onPositionObserverUpdate() {
|
||||
if (controller == null || txtvPosition == null || txtvLength == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
|
||||
int currentPosition = converter.convert(controller.getPosition());
|
||||
int duration = converter.convert(controller.getDuration());
|
||||
int remainingTime = converter.convert(
|
||||
controller.getDuration() - controller.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));
|
||||
}
|
||||
updateProgressbarPosition(currentPosition, duration);
|
||||
}
|
||||
|
||||
private void updateProgressbarPosition(int position, int duration) {
|
||||
Log.d(TAG, "updateProgressbarPosition(" + position + ", " + duration + ")");
|
||||
if(sbPosition == null) {
|
||||
return;
|
||||
}
|
||||
float progress = ((float) position) / duration;
|
||||
sbPosition.setProgress((int) (progress * sbPosition.getMax()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (controller == null || txtvLength == null) {
|
||||
return;
|
||||
}
|
||||
if (fromUser) {
|
||||
prog = progress / ((float) seekBar.getMax());
|
||||
TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
|
||||
int position = converter.convert((int) (prog * controller.getDuration()));
|
||||
txtvSeek.setText(Converter.getDurationStringLong(position));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
cardViewSeek.setScaleX(.8f);
|
||||
cardViewSeek.setScaleY(.8f);
|
||||
cardViewSeek.animate()
|
||||
.setInterpolator(new FastOutSlowInInterpolator())
|
||||
.alpha(1f).scaleX(1f).scaleY(1f)
|
||||
.setDuration(200)
|
||||
.start();
|
||||
videoControlsHider.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
if (controller != null) {
|
||||
controller.seekTo((int) (prog * controller.getDuration()));
|
||||
}
|
||||
cardViewSeek.setScaleX(1f);
|
||||
cardViewSeek.setScaleY(1f);
|
||||
cardViewSeek.animate()
|
||||
.setInterpolator(new FastOutSlowInInterpolator())
|
||||
.alpha(0f).scaleX(.8f).scaleY(.8f)
|
||||
.setDuration(200)
|
||||
.start();
|
||||
setupVideoControlsToggler();
|
||||
}
|
||||
|
||||
private void checkFavorite() {
|
||||
FeedItem feedItem = getFeedItem(controller.getMedia());
|
||||
if (feedItem == null) {
|
||||
return;
|
||||
}
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
disposable = Observable.fromCallable(() -> DBReader.getFeedItem(feedItem.getId()))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
item -> {
|
||||
boolean isFav = item.isTagged(FeedItem.TAG_FAVORITE);
|
||||
if (isFavorite != isFav) {
|
||||
isFavorite = isFav;
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static FeedItem getFeedItem(@Nullable Playable playable) {
|
||||
if (playable instanceof FeedMedia) {
|
||||
return ((FeedMedia) playable).getItem();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void compatEnterPictureInPicture() {
|
||||
|
|
Loading…
Reference in New Issue