Merge branch 'TeamNewPipe:dev' into exo182
This commit is contained in:
commit
f17155bb3f
41 changed files with 663 additions and 667 deletions
|
|
@ -216,7 +216,6 @@ public final class Player implements PlaybackListener, Listener {
|
|||
// minimized to background but will resume automatically to the original player type
|
||||
private boolean isAudioOnly = false;
|
||||
private boolean isPrepared = false;
|
||||
private boolean wasPlaying = false;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// UIs, listeners and disposables
|
||||
|
|
@ -918,13 +917,6 @@ public final class Player implements PlaybackListener, Listener {
|
|||
error -> Log.e(TAG, "Progress update failure: ", error));
|
||||
}
|
||||
|
||||
public void saveWasPlaying() {
|
||||
this.wasPlaying = getPlayWhenReady();
|
||||
}
|
||||
|
||||
public boolean wasPlaying() {
|
||||
return wasPlaying;
|
||||
}
|
||||
//endregion
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -86,8 +86,6 @@ public final class PlayerService extends Service {
|
|||
}
|
||||
|
||||
if (!player.exoPlayerIsNull()) {
|
||||
player.saveWasPlaying();
|
||||
|
||||
// Releases wifi & cpu, disables keepScreenOn, etc.
|
||||
// We can't just pause the player here because it will make transition
|
||||
// from one stream to a new stream not smooth
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package org.schabi.newpipe.player.seekbarpreview;
|
||||
|
||||
import static org.schabi.newpipe.player.seekbarpreview.SeekbarPreviewThumbnailHelper.SeekbarPreviewThumbnailType;
|
||||
import static org.schabi.newpipe.player.seekbarpreview.SeekbarPreviewThumbnailHelper.getSeekbarPreviewThumbnailType;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
|
|
@ -8,6 +9,7 @@ import android.util.Log;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.collection.SparseArrayCompat;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
|
||||
|
|
@ -15,12 +17,9 @@ import org.schabi.newpipe.extractor.stream.Frameset;
|
|||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Supplier;
|
||||
|
|
@ -34,18 +33,15 @@ public class SeekbarPreviewThumbnailHolder {
|
|||
|
||||
// Key = Position of the picture in milliseconds
|
||||
// Supplier = Supplies the bitmap for that position
|
||||
private final Map<Integer, Supplier<Bitmap>> seekbarPreviewData = new ConcurrentHashMap<>();
|
||||
private final SparseArrayCompat<Supplier<Bitmap>> seekbarPreviewData =
|
||||
new SparseArrayCompat<>();
|
||||
|
||||
// This ensures that if the reset is still undergoing
|
||||
// and another reset starts, only the last reset is processed
|
||||
private UUID currentUpdateRequestIdentifier = UUID.randomUUID();
|
||||
|
||||
public synchronized void resetFrom(
|
||||
@NonNull final Context context,
|
||||
final List<Frameset> framesets) {
|
||||
|
||||
final int seekbarPreviewType =
|
||||
SeekbarPreviewThumbnailHelper.getSeekbarPreviewThumbnailType(context);
|
||||
public void resetFrom(@NonNull final Context context, final List<Frameset> framesets) {
|
||||
final int seekbarPreviewType = getSeekbarPreviewThumbnailType(context);
|
||||
|
||||
final UUID updateRequestIdentifier = UUID.randomUUID();
|
||||
this.currentUpdateRequestIdentifier = updateRequestIdentifier;
|
||||
|
|
@ -63,13 +59,12 @@ public class SeekbarPreviewThumbnailHolder {
|
|||
executorService.shutdown();
|
||||
}
|
||||
|
||||
private void resetFromAsync(
|
||||
final int seekbarPreviewType,
|
||||
final List<Frameset> framesets,
|
||||
final UUID updateRequestIdentifier) {
|
||||
|
||||
private void resetFromAsync(final int seekbarPreviewType, final List<Frameset> framesets,
|
||||
final UUID updateRequestIdentifier) {
|
||||
Log.d(TAG, "Clearing seekbarPreviewData");
|
||||
seekbarPreviewData.clear();
|
||||
synchronized (seekbarPreviewData) {
|
||||
seekbarPreviewData.clear();
|
||||
}
|
||||
|
||||
if (seekbarPreviewType == SeekbarPreviewThumbnailType.NONE) {
|
||||
Log.d(TAG, "Not processing seekbarPreviewData due to settings");
|
||||
|
|
@ -94,10 +89,8 @@ public class SeekbarPreviewThumbnailHolder {
|
|||
generateDataFrom(frameset, updateRequestIdentifier);
|
||||
}
|
||||
|
||||
private Frameset getFrameSetForType(
|
||||
final List<Frameset> framesets,
|
||||
final int seekbarPreviewType) {
|
||||
|
||||
private Frameset getFrameSetForType(final List<Frameset> framesets,
|
||||
final int seekbarPreviewType) {
|
||||
if (seekbarPreviewType == SeekbarPreviewThumbnailType.HIGH_QUALITY) {
|
||||
Log.d(TAG, "Strategy for seekbarPreviewData: high quality");
|
||||
return framesets.stream()
|
||||
|
|
@ -111,17 +104,14 @@ public class SeekbarPreviewThumbnailHolder {
|
|||
}
|
||||
}
|
||||
|
||||
private void generateDataFrom(
|
||||
final Frameset frameset,
|
||||
final UUID updateRequestIdentifier) {
|
||||
|
||||
private void generateDataFrom(final Frameset frameset, final UUID updateRequestIdentifier) {
|
||||
Log.d(TAG, "Starting generation of seekbarPreviewData");
|
||||
final Stopwatch sw = Log.isLoggable(TAG, Log.DEBUG) ? Stopwatch.createStarted() : null;
|
||||
|
||||
int currentPosMs = 0;
|
||||
int pos = 1;
|
||||
|
||||
final int frameCountPerUrl = frameset.getFramesPerPageX() * frameset.getFramesPerPageY();
|
||||
final int urlFrameCount = frameset.getFramesPerPageX() * frameset.getFramesPerPageY();
|
||||
|
||||
// Process each url in the frameset
|
||||
for (final String url : frameset.getUrls()) {
|
||||
|
|
@ -130,11 +120,11 @@ public class SeekbarPreviewThumbnailHolder {
|
|||
|
||||
// The data is not added directly to "seekbarPreviewData" due to
|
||||
// concurrency and checks for "updateRequestIdentifier"
|
||||
final Map<Integer, Supplier<Bitmap>> generatedDataForUrl = new HashMap<>();
|
||||
final var generatedDataForUrl = new SparseArrayCompat<Supplier<Bitmap>>(urlFrameCount);
|
||||
|
||||
// The bitmap consists of several images, which we process here
|
||||
// foreach frame in the returned bitmap
|
||||
for (int i = 0; i < frameCountPerUrl; i++) {
|
||||
for (int i = 0; i < urlFrameCount; i++) {
|
||||
// Frames outside the video length are skipped
|
||||
if (pos > frameset.getTotalCount()) {
|
||||
break;
|
||||
|
|
@ -161,7 +151,9 @@ public class SeekbarPreviewThumbnailHolder {
|
|||
// Check if we are still the latest request
|
||||
// If not abort method execution
|
||||
if (isRequestIdentifierCurrent(updateRequestIdentifier)) {
|
||||
seekbarPreviewData.putAll(generatedDataForUrl);
|
||||
synchronized (seekbarPreviewData) {
|
||||
seekbarPreviewData.putAll(generatedDataForUrl);
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Aborted of generation of seekbarPreviewData");
|
||||
break;
|
||||
|
|
@ -169,7 +161,7 @@ public class SeekbarPreviewThumbnailHolder {
|
|||
}
|
||||
|
||||
if (sw != null) {
|
||||
Log.d(TAG, "Generation of seekbarPreviewData took " + sw.stop().toString());
|
||||
Log.d(TAG, "Generation of seekbarPreviewData took " + sw.stop());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -189,17 +181,14 @@ public class SeekbarPreviewThumbnailHolder {
|
|||
final Bitmap bitmap = PicassoHelper.loadSeekbarThumbnailPreview(url).get();
|
||||
|
||||
if (sw != null) {
|
||||
Log.d(TAG,
|
||||
"Download of bitmap for seekbarPreview from '" + url
|
||||
+ "' took " + sw.stop().toString());
|
||||
Log.d(TAG, "Download of bitmap for seekbarPreview from '" + url + "' took "
|
||||
+ sw.stop());
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
} catch (final Exception ex) {
|
||||
Log.w(TAG,
|
||||
"Failed to get bitmap for seekbarPreview from url='" + url
|
||||
+ "' in time",
|
||||
ex);
|
||||
Log.w(TAG, "Failed to get bitmap for seekbarPreview from url='" + url
|
||||
+ "' in time", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -208,32 +197,20 @@ public class SeekbarPreviewThumbnailHolder {
|
|||
return this.currentUpdateRequestIdentifier.equals(requestIdentifier);
|
||||
}
|
||||
|
||||
|
||||
public Optional<Bitmap> getBitmapAt(final int positionInMs) {
|
||||
// Check if the BitmapData is empty
|
||||
if (seekbarPreviewData.isEmpty()) {
|
||||
return Optional.empty();
|
||||
// Get the frame supplier closest to the requested position
|
||||
Supplier<Bitmap> closestFrame = () -> null;
|
||||
synchronized (seekbarPreviewData) {
|
||||
int min = Integer.MAX_VALUE;
|
||||
for (int i = 0; i < seekbarPreviewData.size(); i++) {
|
||||
final int pos = Math.abs(seekbarPreviewData.keyAt(i) - positionInMs);
|
||||
if (pos < min) {
|
||||
closestFrame = seekbarPreviewData.valueAt(i);
|
||||
min = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the closest frame to the requested position
|
||||
final int closestIndexPosition =
|
||||
seekbarPreviewData.keySet().stream()
|
||||
.min(Comparator.comparingInt(i -> Math.abs(i - positionInMs)))
|
||||
.orElse(-1);
|
||||
|
||||
// this should never happen, because
|
||||
// it indicates that "seekbarPreviewData" is empty which was already checked
|
||||
if (closestIndexPosition == -1) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the bitmap for the position (executes the supplier)
|
||||
return Optional.ofNullable(seekbarPreviewData.get(closestIndexPosition).get());
|
||||
} catch (final Exception ex) {
|
||||
// If there is an error, log it and return Optional.empty
|
||||
Log.w(TAG, "Unable to get seekbar preview", ex);
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.ofNullable(closestFrame.get());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,6 +154,16 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
|
|||
protected void initListeners() {
|
||||
super.initListeners();
|
||||
|
||||
binding.screenRotationButton.setOnClickListener(makeOnClickListener(() -> {
|
||||
// Only if it's not a vertical video or vertical video but in landscape with locked
|
||||
// orientation a screen orientation can be changed automatically
|
||||
if (!isVerticalVideo || (isLandscape() && globalScreenOrientationLocked(context))) {
|
||||
player.getFragmentListener()
|
||||
.ifPresent(PlayerServiceEventListener::onScreenRotationButtonClicked);
|
||||
} else {
|
||||
toggleFullscreen();
|
||||
}
|
||||
}));
|
||||
binding.queueButton.setOnClickListener(v -> onQueueClicked());
|
||||
binding.segmentsButton.setOnClickListener(v -> onSegmentsClicked());
|
||||
|
||||
|
|
@ -173,6 +183,14 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
|
|||
settingsContentObserver);
|
||||
|
||||
binding.getRoot().addOnLayoutChangeListener(this);
|
||||
|
||||
binding.moreOptionsButton.setOnLongClickListener(v -> {
|
||||
player.getFragmentListener()
|
||||
.ifPresent(PlayerServiceEventListener::onMoreOptionsLongClicked);
|
||||
hideControls(0, 0);
|
||||
hideSystemUIIfNeeded();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -846,23 +864,6 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
|
|||
//////////////////////////////////////////////////////////////////////////*/
|
||||
//region Click listeners
|
||||
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
if (v.getId() == binding.screenRotationButton.getId()) {
|
||||
// Only if it's not a vertical video or vertical video but in landscape with locked
|
||||
// orientation a screen orientation can be changed automatically
|
||||
if (!isVerticalVideo || (isLandscape() && globalScreenOrientationLocked(context))) {
|
||||
player.getFragmentListener().ifPresent(
|
||||
PlayerServiceEventListener::onScreenRotationButtonClicked);
|
||||
} else {
|
||||
toggleFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
// call it later since it calls manageControlsAfterOnClick at the end
|
||||
super.onClick(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPlaybackSpeedClicked() {
|
||||
final AppCompatActivity activity = getParentActivity().orElse(null);
|
||||
|
|
@ -875,18 +876,6 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
|
|||
.show(activity.getSupportFragmentManager(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(final View v) {
|
||||
if (v.getId() == binding.moreOptionsButton.getId() && isFullscreen) {
|
||||
player.getFragmentListener().ifPresent(
|
||||
PlayerServiceEventListener::onMoreOptionsLongClicked);
|
||||
hideControls(0, 0);
|
||||
hideSystemUIIfNeeded();
|
||||
return true;
|
||||
}
|
||||
return super.onLongClick(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(final int keyCode) {
|
||||
if (keyCode == KeyEvent.KEYCODE_SPACE && isFullscreen) {
|
||||
|
|
|
|||
|
|
@ -84,11 +84,11 @@ import org.schabi.newpipe.util.external_communication.ShareUtils;
|
|||
import org.schabi.newpipe.views.player.PlayerFastSeekOverlay;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class VideoPlayerUi extends PlayerUi
|
||||
implements SeekBar.OnSeekBarChangeListener, View.OnClickListener, View.OnLongClickListener,
|
||||
public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBarChangeListener,
|
||||
PopupMenu.OnMenuItemClickListener, PopupMenu.OnDismissListener {
|
||||
private static final String TAG = VideoPlayerUi.class.getSimpleName();
|
||||
|
||||
|
|
@ -132,9 +132,11 @@ public abstract class VideoPlayerUi extends PlayerUi
|
|||
|
||||
private GestureDetector gestureDetector;
|
||||
private BasePlayerGestureListener playerGestureListener;
|
||||
@Nullable private View.OnLayoutChangeListener onLayoutChangeListener = null;
|
||||
@Nullable
|
||||
private View.OnLayoutChangeListener onLayoutChangeListener = null;
|
||||
|
||||
@NonNull private final SeekbarPreviewThumbnailHolder seekbarPreviewThumbnailHolder =
|
||||
@NonNull
|
||||
private final SeekbarPreviewThumbnailHolder seekbarPreviewThumbnailHolder =
|
||||
new SeekbarPreviewThumbnailHolder();
|
||||
|
||||
|
||||
|
|
@ -187,13 +189,13 @@ public abstract class VideoPlayerUi extends PlayerUi
|
|||
abstract BasePlayerGestureListener buildGestureListener();
|
||||
|
||||
protected void initListeners() {
|
||||
binding.qualityTextView.setOnClickListener(this);
|
||||
binding.playbackSpeed.setOnClickListener(this);
|
||||
binding.qualityTextView.setOnClickListener(makeOnClickListener(this::onQualityClicked));
|
||||
binding.playbackSpeed.setOnClickListener(makeOnClickListener(this::onPlaybackSpeedClicked));
|
||||
|
||||
binding.playbackSeekBar.setOnSeekBarChangeListener(this);
|
||||
binding.captionTextView.setOnClickListener(this);
|
||||
binding.resizeTextView.setOnClickListener(this);
|
||||
binding.playbackLiveSync.setOnClickListener(this);
|
||||
binding.captionTextView.setOnClickListener(makeOnClickListener(this::onCaptionClicked));
|
||||
binding.resizeTextView.setOnClickListener(makeOnClickListener(this::onResizeClicked));
|
||||
binding.playbackLiveSync.setOnClickListener(makeOnClickListener(player::seekToDefault));
|
||||
|
||||
playerGestureListener = buildGestureListener();
|
||||
gestureDetector = new GestureDetector(context, playerGestureListener);
|
||||
|
|
@ -202,20 +204,36 @@ public abstract class VideoPlayerUi extends PlayerUi
|
|||
binding.repeatButton.setOnClickListener(v -> onRepeatClicked());
|
||||
binding.shuffleButton.setOnClickListener(v -> onShuffleClicked());
|
||||
|
||||
binding.playPauseButton.setOnClickListener(this);
|
||||
binding.playPreviousButton.setOnClickListener(this);
|
||||
binding.playNextButton.setOnClickListener(this);
|
||||
binding.playPauseButton.setOnClickListener(makeOnClickListener(player::playPause));
|
||||
binding.playPreviousButton.setOnClickListener(makeOnClickListener(player::playPrevious));
|
||||
binding.playNextButton.setOnClickListener(makeOnClickListener(player::playNext));
|
||||
|
||||
binding.moreOptionsButton.setOnClickListener(this);
|
||||
binding.moreOptionsButton.setOnLongClickListener(this);
|
||||
binding.share.setOnClickListener(this);
|
||||
binding.share.setOnLongClickListener(this);
|
||||
binding.fullScreenButton.setOnClickListener(this);
|
||||
binding.screenRotationButton.setOnClickListener(this);
|
||||
binding.playWithKodi.setOnClickListener(this);
|
||||
binding.openInBrowser.setOnClickListener(this);
|
||||
binding.playerCloseButton.setOnClickListener(this);
|
||||
binding.switchMute.setOnClickListener(this);
|
||||
binding.moreOptionsButton.setOnClickListener(
|
||||
makeOnClickListener(this::onMoreOptionsClicked));
|
||||
binding.share.setOnClickListener(makeOnClickListener(() -> {
|
||||
final PlayQueueItem currentItem = player.getCurrentItem();
|
||||
if (currentItem != null) {
|
||||
ShareUtils.shareText(context, currentItem.getTitle(),
|
||||
player.getVideoUrlAtCurrentTime(), currentItem.getThumbnailUrl());
|
||||
}
|
||||
}));
|
||||
binding.share.setOnLongClickListener(v -> {
|
||||
ShareUtils.copyToClipboard(context, player.getVideoUrlAtCurrentTime());
|
||||
return true;
|
||||
});
|
||||
binding.fullScreenButton.setOnClickListener(makeOnClickListener(() -> {
|
||||
player.setRecovery();
|
||||
NavigationHelper.playOnMainPlayer(context,
|
||||
Objects.requireNonNull(player.getPlayQueue()), true);
|
||||
}));
|
||||
binding.playWithKodi.setOnClickListener(makeOnClickListener(this::onPlayWithKodiClicked));
|
||||
binding.openInBrowser.setOnClickListener(makeOnClickListener(this::onOpenInBrowserClicked));
|
||||
binding.playerCloseButton.setOnClickListener(makeOnClickListener(() ->
|
||||
// set package to this app's package to prevent the intent from being seen outside
|
||||
context.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER)
|
||||
.setPackage(App.PACKAGE_NAME))
|
||||
));
|
||||
binding.switchMute.setOnClickListener(makeOnClickListener(player::toggleMute));
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.itemsListPanel, (view, windowInsets) -> {
|
||||
final Insets cutout = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout());
|
||||
|
|
@ -229,11 +247,8 @@ public abstract class VideoPlayerUi extends PlayerUi
|
|||
// player_overlays and fast_seek_overlay too. Without it they will be off-centered.
|
||||
onLayoutChangeListener =
|
||||
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
||||
binding.playerOverlays.setPadding(
|
||||
v.getPaddingLeft(),
|
||||
v.getPaddingTop(),
|
||||
v.getPaddingRight(),
|
||||
v.getPaddingBottom());
|
||||
binding.playerOverlays.setPadding(v.getPaddingLeft(), v.getPaddingTop(),
|
||||
v.getPaddingRight(), v.getPaddingBottom());
|
||||
|
||||
// If we added padding to the fast seek overlay, too, it would not go under the
|
||||
// system ui. Instead we apply negative margins equal to the window insets of
|
||||
|
|
@ -603,11 +618,6 @@ public abstract class VideoPlayerUi extends PlayerUi
|
|||
player.changeState(STATE_PAUSED_SEEK);
|
||||
}
|
||||
|
||||
player.saveWasPlaying();
|
||||
if (player.isPlaying()) {
|
||||
player.getExoPlayer().pause();
|
||||
}
|
||||
|
||||
showControls(0);
|
||||
animate(binding.currentDisplaySeek, true, DEFAULT_CONTROLS_DURATION,
|
||||
AnimationType.SCALE_AND_ALPHA);
|
||||
|
|
@ -622,7 +632,7 @@ public abstract class VideoPlayerUi extends PlayerUi
|
|||
}
|
||||
|
||||
player.seekTo(seekBar.getProgress());
|
||||
if (player.wasPlaying() || player.getExoPlayer().getDuration() == seekBar.getProgress()) {
|
||||
if (player.getExoPlayer().getDuration() == seekBar.getProgress()) {
|
||||
player.getExoPlayer().play();
|
||||
}
|
||||
|
||||
|
|
@ -636,9 +646,8 @@ public abstract class VideoPlayerUi extends PlayerUi
|
|||
if (!player.isProgressLoopRunning()) {
|
||||
player.startProgressLoop();
|
||||
}
|
||||
if (player.wasPlaying()) {
|
||||
showControlsThenHide();
|
||||
}
|
||||
|
||||
showControlsThenHide();
|
||||
}
|
||||
//endregion
|
||||
|
||||
|
|
@ -1173,8 +1182,6 @@ public abstract class VideoPlayerUi extends PlayerUi
|
|||
binding.qualityTextView.setText(MediaFormat.getNameById(videoStream.getFormatId())
|
||||
+ " " + videoStream.getResolution());
|
||||
}
|
||||
|
||||
player.saveWasPlaying();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1326,86 +1333,39 @@ public abstract class VideoPlayerUi extends PlayerUi
|
|||
//////////////////////////////////////////////////////////////////////////*/
|
||||
//region Click listeners
|
||||
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onClick() called with: v = [" + v + "]");
|
||||
}
|
||||
if (v.getId() == binding.resizeTextView.getId()) {
|
||||
onResizeClicked();
|
||||
} else if (v.getId() == binding.captionTextView.getId()) {
|
||||
onCaptionClicked();
|
||||
} else if (v.getId() == binding.playbackLiveSync.getId()) {
|
||||
player.seekToDefault();
|
||||
} else if (v.getId() == binding.playPauseButton.getId()) {
|
||||
player.playPause();
|
||||
} else if (v.getId() == binding.playPreviousButton.getId()) {
|
||||
player.playPrevious();
|
||||
} else if (v.getId() == binding.playNextButton.getId()) {
|
||||
player.playNext();
|
||||
} else if (v.getId() == binding.moreOptionsButton.getId()) {
|
||||
onMoreOptionsClicked();
|
||||
} else if (v.getId() == binding.share.getId()) {
|
||||
final PlayQueueItem currentItem = player.getCurrentItem();
|
||||
if (currentItem != null) {
|
||||
ShareUtils.shareText(context, currentItem.getTitle(),
|
||||
player.getVideoUrlAtCurrentTime(), currentItem.getThumbnailUrl());
|
||||
}
|
||||
} else if (v.getId() == binding.playWithKodi.getId()) {
|
||||
onPlayWithKodiClicked();
|
||||
} else if (v.getId() == binding.openInBrowser.getId()) {
|
||||
onOpenInBrowserClicked();
|
||||
} else if (v.getId() == binding.fullScreenButton.getId()) {
|
||||
player.setRecovery();
|
||||
NavigationHelper.playOnMainPlayer(context, player.getPlayQueue(), true);
|
||||
return;
|
||||
} else if (v.getId() == binding.switchMute.getId()) {
|
||||
player.toggleMute();
|
||||
} else if (v.getId() == binding.playerCloseButton.getId()) {
|
||||
// set package to this app's package to prevent the intent from being seen outside
|
||||
context.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER)
|
||||
.setPackage(App.PACKAGE_NAME));
|
||||
} else if (v.getId() == binding.playbackSpeed.getId()) {
|
||||
onPlaybackSpeedClicked();
|
||||
} else if (v.getId() == binding.qualityTextView.getId()) {
|
||||
onQualityClicked();
|
||||
}
|
||||
|
||||
manageControlsAfterOnClick(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages the controls after a click occurred on the player UI.
|
||||
* @param v – The view that was clicked
|
||||
* Create on-click listener which manages the player controls after the view on-click action.
|
||||
*
|
||||
* @param runnable The action to be executed.
|
||||
* @return The view click listener.
|
||||
*/
|
||||
public void manageControlsAfterOnClick(@NonNull final View v) {
|
||||
if (player.getCurrentState() == STATE_COMPLETED) {
|
||||
return;
|
||||
}
|
||||
protected View.OnClickListener makeOnClickListener(@NonNull final Runnable runnable) {
|
||||
return v -> {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onClick() called with: v = [" + v + "]");
|
||||
}
|
||||
|
||||
controlsVisibilityHandler.removeCallbacksAndMessages(null);
|
||||
showHideShadow(true, DEFAULT_CONTROLS_DURATION);
|
||||
animate(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION,
|
||||
AnimationType.ALPHA, 0, () -> {
|
||||
if (player.getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible) {
|
||||
if (v.getId() == binding.playPauseButton.getId()
|
||||
// Hide controls in fullscreen immediately
|
||||
|| (v.getId() == binding.screenRotationButton.getId()
|
||||
&& isFullscreen())) {
|
||||
hideControls(0, 0);
|
||||
} else {
|
||||
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
|
||||
runnable.run();
|
||||
|
||||
// Manages the player controls after handling the view click.
|
||||
if (player.getCurrentState() == STATE_COMPLETED) {
|
||||
return;
|
||||
}
|
||||
controlsVisibilityHandler.removeCallbacksAndMessages(null);
|
||||
showHideShadow(true, DEFAULT_CONTROLS_DURATION);
|
||||
animate(binding.playbackControlRoot, true, DEFAULT_CONTROLS_DURATION,
|
||||
AnimationType.ALPHA, 0, () -> {
|
||||
if (player.getCurrentState() == STATE_PLAYING && !isSomePopupMenuVisible) {
|
||||
if (v == binding.playPauseButton
|
||||
// Hide controls in fullscreen immediately
|
||||
|| (v == binding.screenRotationButton && isFullscreen())) {
|
||||
hideControls(0, 0);
|
||||
} else {
|
||||
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(final View v) {
|
||||
if (v.getId() == binding.share.getId()) {
|
||||
ShareUtils.copyToClipboard(context, player.getVideoUrlAtCurrentTime());
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
public boolean onKeyDown(final int keyCode) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue