mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-01-11 01:40:59 +00:00
Merge pull request #4562 from Stypox/fix-detail-open
Fix opening VideoDetailFragment and much more
This commit is contained in:
commit
c4a739bef6
@ -30,9 +30,7 @@ import android.os.Build;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import androidx.preference.PreferenceManager;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@ -46,6 +44,7 @@ import android.widget.FrameLayout;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||||
@ -55,6 +54,7 @@ import androidx.core.view.GravityCompat;
|
|||||||
import androidx.drawerlayout.widget.DrawerLayout;
|
import androidx.drawerlayout.widget.DrawerLayout;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
import com.google.android.material.navigation.NavigationView;
|
import com.google.android.material.navigation.NavigationView;
|
||||||
@ -69,10 +69,11 @@ import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
|
|||||||
import org.schabi.newpipe.fragments.list.search.SearchFragment;
|
import org.schabi.newpipe.fragments.list.search.SearchFragment;
|
||||||
import org.schabi.newpipe.player.VideoPlayer;
|
import org.schabi.newpipe.player.VideoPlayer;
|
||||||
import org.schabi.newpipe.player.event.OnKeyDownListener;
|
import org.schabi.newpipe.player.event.OnKeyDownListener;
|
||||||
|
import org.schabi.newpipe.player.helper.PlayerHolder;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.util.DeviceUtils;
|
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
|
import org.schabi.newpipe.util.DeviceUtils;
|
||||||
import org.schabi.newpipe.util.KioskTranslator;
|
import org.schabi.newpipe.util.KioskTranslator;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
@ -87,6 +88,7 @@ import org.schabi.newpipe.views.FocusOverlayView;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||||
|
|
||||||
@ -152,7 +154,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
if (DeviceUtils.isTv(this)) {
|
if (DeviceUtils.isTv(this)) {
|
||||||
FocusOverlayView.setupFocusObserver(this);
|
FocusOverlayView.setupFocusObserver(this);
|
||||||
}
|
}
|
||||||
setupBroadcastReceiver();
|
openMiniPlayerUponPlayerStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupDrawer() throws Exception {
|
private void setupDrawer() throws Exception {
|
||||||
@ -758,32 +760,36 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
if (intent.hasExtra(Constants.KEY_LINK_TYPE)) {
|
if (intent.hasExtra(Constants.KEY_LINK_TYPE)) {
|
||||||
final String url = intent.getStringExtra(Constants.KEY_URL);
|
final String url = intent.getStringExtra(Constants.KEY_URL);
|
||||||
final int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
final int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
||||||
final String title = intent.getStringExtra(Constants.KEY_TITLE);
|
String title = intent.getStringExtra(Constants.KEY_TITLE);
|
||||||
switch (((StreamingService.LinkType) intent
|
if (title == null) {
|
||||||
.getSerializableExtra(Constants.KEY_LINK_TYPE))) {
|
title = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
final StreamingService.LinkType linkType = ((StreamingService.LinkType) intent
|
||||||
|
.getSerializableExtra(Constants.KEY_LINK_TYPE));
|
||||||
|
assert linkType != null;
|
||||||
|
switch (linkType) {
|
||||||
case STREAM:
|
case STREAM:
|
||||||
final boolean autoPlay = intent
|
final String intentCacheKey = intent.getStringExtra(
|
||||||
.getBooleanExtra(VideoDetailFragment.AUTO_PLAY, false);
|
VideoPlayer.PLAY_QUEUE_KEY);
|
||||||
final String intentCacheKey = intent
|
|
||||||
.getStringExtra(VideoPlayer.PLAY_QUEUE_KEY);
|
|
||||||
final PlayQueue playQueue = intentCacheKey != null
|
final PlayQueue playQueue = intentCacheKey != null
|
||||||
? SerializedCache.getInstance()
|
? SerializedCache.getInstance()
|
||||||
.take(intentCacheKey, PlayQueue.class)
|
.take(intentCacheKey, PlayQueue.class)
|
||||||
: null;
|
: null;
|
||||||
NavigationHelper.openVideoDetailFragment(getSupportFragmentManager(),
|
|
||||||
serviceId, url, title, autoPlay, playQueue);
|
final boolean switchingPlayers = intent.getBooleanExtra(
|
||||||
|
VideoDetailFragment.KEY_SWITCHING_PLAYERS, false);
|
||||||
|
NavigationHelper.openVideoDetailFragment(
|
||||||
|
getApplicationContext(), getSupportFragmentManager(),
|
||||||
|
serviceId, url, title, playQueue, switchingPlayers);
|
||||||
break;
|
break;
|
||||||
case CHANNEL:
|
case CHANNEL:
|
||||||
NavigationHelper.openChannelFragment(getSupportFragmentManager(),
|
NavigationHelper.openChannelFragment(getSupportFragmentManager(),
|
||||||
serviceId,
|
serviceId, url, title);
|
||||||
url,
|
|
||||||
title);
|
|
||||||
break;
|
break;
|
||||||
case PLAYLIST:
|
case PLAYLIST:
|
||||||
NavigationHelper.openPlaylistFragment(getSupportFragmentManager(),
|
NavigationHelper.openPlaylistFragment(getSupportFragmentManager(),
|
||||||
serviceId,
|
serviceId, url, title);
|
||||||
url,
|
|
||||||
title);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (intent.hasExtra(Constants.KEY_OPEN_SEARCH)) {
|
} else if (intent.hasExtra(Constants.KEY_OPEN_SEARCH)) {
|
||||||
@ -805,26 +811,38 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupBroadcastReceiver() {
|
private void openMiniPlayerIfMissing() {
|
||||||
broadcastReceiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
|
||||||
if (intent.getAction().equals(VideoDetailFragment.ACTION_PLAYER_STARTED)) {
|
|
||||||
final Fragment fragmentPlayer = getSupportFragmentManager()
|
final Fragment fragmentPlayer = getSupportFragmentManager()
|
||||||
.findFragmentById(R.id.fragment_player_holder);
|
.findFragmentById(R.id.fragment_player_holder);
|
||||||
if (fragmentPlayer == null) {
|
if (fragmentPlayer == null) {
|
||||||
/*
|
// We still don't have a fragment attached to the activity. It can happen when a user
|
||||||
* We still don't have a fragment attached to the activity.
|
// started popup or background players without opening a stream inside the fragment.
|
||||||
* It can happen when a user started popup or background players
|
// Adding it in a collapsed state (only mini player will be visible).
|
||||||
* without opening a stream inside the fragment.
|
|
||||||
* Adding it in a collapsed state (only mini player will be visible)
|
|
||||||
* */
|
|
||||||
NavigationHelper.showMiniPlayer(getSupportFragmentManager());
|
NavigationHelper.showMiniPlayer(getSupportFragmentManager());
|
||||||
}
|
}
|
||||||
/*
|
}
|
||||||
* At this point the player is added 100%, we can unregister.
|
|
||||||
* Other actions are useless since the fragment will not be removed after that
|
private void openMiniPlayerUponPlayerStarted() {
|
||||||
* */
|
if (getIntent().getSerializableExtra(Constants.KEY_LINK_TYPE)
|
||||||
|
== StreamingService.LinkType.STREAM) {
|
||||||
|
// handleIntent() already takes care of opening video detail fragment
|
||||||
|
// due to an intent containing a STREAM link
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PlayerHolder.isPlayerOpen()) {
|
||||||
|
// if the player is already open, no need for a broadcast receiver
|
||||||
|
openMiniPlayerIfMissing();
|
||||||
|
} else {
|
||||||
|
// listen for player start intent being sent around
|
||||||
|
broadcastReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
|
if (Objects.equals(intent.getAction(),
|
||||||
|
VideoDetailFragment.ACTION_PLAYER_STARTED)) {
|
||||||
|
openMiniPlayerIfMissing();
|
||||||
|
// At this point the player is added 100%, we can unregister. Other actions
|
||||||
|
// are useless since the fragment will not be removed after that.
|
||||||
unregisterReceiver(broadcastReceiver);
|
unregisterReceiver(broadcastReceiver);
|
||||||
broadcastReceiver = null;
|
broadcastReceiver = null;
|
||||||
}
|
}
|
||||||
@ -834,6 +852,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
intentFilter.addAction(VideoDetailFragment.ACTION_PLAYER_STARTED);
|
intentFilter.addAction(VideoDetailFragment.ACTION_PLAYER_STARTED);
|
||||||
registerReceiver(broadcastReceiver, intentFilter);
|
registerReceiver(broadcastReceiver, intentFilter);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean bottomSheetHiddenOrCollapsed() {
|
private boolean bottomSheetHiddenOrCollapsed() {
|
||||||
final FrameLayout bottomSheetLayout = findViewById(R.id.fragment_player_holder);
|
final FrameLayout bottomSheetLayout = findViewById(R.id.fragment_player_holder);
|
||||||
|
@ -40,7 +40,9 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
|||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
|
import org.schabi.newpipe.player.MainPlayer;
|
||||||
import org.schabi.newpipe.player.helper.PlayerHelper;
|
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||||
|
import org.schabi.newpipe.player.helper.PlayerHolder;
|
||||||
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
||||||
@ -60,8 +62,6 @@ import org.schabi.newpipe.views.FocusOverlayView;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import icepick.Icepick;
|
import icepick.Icepick;
|
||||||
@ -116,8 +116,6 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internalRoute = getIntent().getBooleanExtra(INTERNAL_ROUTE_KEY, false);
|
|
||||||
|
|
||||||
setTheme(ThemeHelper.isLightThemeSelected(this)
|
setTheme(ThemeHelper.isLightThemeSelected(this)
|
||||||
? R.style.RouterActivityThemeLight : R.style.RouterActivityThemeDark);
|
? R.style.RouterActivityThemeLight : R.style.RouterActivityThemeDark);
|
||||||
}
|
}
|
||||||
@ -398,15 +396,23 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
// show both "show info" and "video player", they are two different activities
|
// show both "show info" and "video player", they are two different activities
|
||||||
returnList.add(showInfo);
|
returnList.add(showInfo);
|
||||||
returnList.add(videoPlayer);
|
returnList.add(videoPlayer);
|
||||||
} else if (capabilities.contains(VIDEO)
|
|
||||||
&& PlayerHelper.isAutoplayAllowedByUser(context)) {
|
|
||||||
// show only "video player" since the details activity will be opened and the video
|
|
||||||
// will be autoplayed there and "show info" would do the exact same thing
|
|
||||||
returnList.add(videoPlayer);
|
|
||||||
} else {
|
} else {
|
||||||
// show only "show info" if video player is not applicable or autoplay is disabled
|
final MainPlayer.PlayerType playerType = PlayerHolder.getType();
|
||||||
|
if (capabilities.contains(VIDEO)
|
||||||
|
&& PlayerHelper.isAutoplayAllowedByUser(context)
|
||||||
|
&& playerType == null || playerType == MainPlayer.PlayerType.VIDEO) {
|
||||||
|
// show only "video player" since the details activity will be opened and the
|
||||||
|
// video will be auto played there. Since "show info" would do the exact same
|
||||||
|
// thing, use that as a key to let VideoDetailFragment load the stream instead
|
||||||
|
// of using FetcherService (see comment in handleChoice())
|
||||||
|
returnList.add(new AdapterChoiceItem(
|
||||||
|
showInfo.key, videoPlayer.description, videoPlayer.icon));
|
||||||
|
} else {
|
||||||
|
// show only "show info" if video player is not applicable, auto play is
|
||||||
|
// disabled or a video is playing in a player different than the main one
|
||||||
returnList.add(showInfo);
|
returnList.add(showInfo);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (capabilities.contains(VIDEO)) {
|
if (capabilities.contains(VIDEO)) {
|
||||||
returnList.add(popupPlayer);
|
returnList.add(popupPlayer);
|
||||||
@ -492,12 +498,7 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(intent -> {
|
.subscribe(intent -> {
|
||||||
if (!internalRoute) {
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
|
||||||
}
|
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
}, throwable -> handleError(throwable, currentUrl))
|
}, throwable -> handleError(throwable, currentUrl))
|
||||||
);
|
);
|
||||||
@ -515,7 +516,7 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
private void openDownloadDialog() {
|
private void openDownloadDialog() {
|
||||||
ExtractorHelper.getStreamInfo(currentServiceId, currentUrl, true)
|
disposables.add(ExtractorHelper.getStreamInfo(currentServiceId, currentUrl, true)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe((@NonNull StreamInfo result) -> {
|
.subscribe((@NonNull StreamInfo result) -> {
|
||||||
@ -532,10 +533,10 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
|
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
|
||||||
downloadDialog.show(fm, "downloadDialog");
|
downloadDialog.show(fm, "downloadDialog");
|
||||||
fm.executePendingTransactions();
|
fm.executePendingTransactions();
|
||||||
downloadDialog.getDialog().setOnDismissListener(dialog -> finish());
|
downloadDialog.requireDialog().setOnDismissListener(dialog -> finish());
|
||||||
}, (@NonNull Throwable throwable) -> {
|
}, (@NonNull Throwable throwable) -> {
|
||||||
showUnsupportedUrlDialog(currentUrl);
|
showUnsupportedUrlDialog(currentUrl);
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -553,66 +554,6 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Service Fetcher
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private String removeHeadingGibberish(final String input) {
|
|
||||||
int start = 0;
|
|
||||||
for (int i = input.indexOf("://") - 1; i >= 0; i--) {
|
|
||||||
if (!input.substring(i, i + 1).matches("\\p{L}")) {
|
|
||||||
start = i + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return input.substring(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Utils
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private String trim(final String input) {
|
|
||||||
if (input == null || input.length() < 1) {
|
|
||||||
return input;
|
|
||||||
} else {
|
|
||||||
String output = input;
|
|
||||||
while (output.length() > 0 && output.substring(0, 1).matches(REGEX_REMOVE_FROM_URL)) {
|
|
||||||
output = output.substring(1);
|
|
||||||
}
|
|
||||||
while (output.length() > 0
|
|
||||||
&& output.substring(output.length() - 1).matches(REGEX_REMOVE_FROM_URL)) {
|
|
||||||
output = output.substring(0, output.length() - 1);
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves all Strings which look remotely like URLs from a text.
|
|
||||||
* Used if NewPipe was called through share menu.
|
|
||||||
*
|
|
||||||
* @param sharedText text to scan for URLs.
|
|
||||||
* @return potential URLs
|
|
||||||
*/
|
|
||||||
protected String[] getUris(final String sharedText) {
|
|
||||||
final Collection<String> result = new HashSet<>();
|
|
||||||
if (sharedText != null) {
|
|
||||||
final String[] array = sharedText.split("\\p{Space}");
|
|
||||||
for (String s : array) {
|
|
||||||
s = trim(s);
|
|
||||||
if (s.length() != 0) {
|
|
||||||
if (s.matches(".+://.+")) {
|
|
||||||
result.add(removeHeadingGibberish(s));
|
|
||||||
} else if (s.matches(".+\\..+")) {
|
|
||||||
result.add("http://" + s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result.toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class AdapterChoiceItem {
|
private static class AdapterChoiceItem {
|
||||||
final String description;
|
final String description;
|
||||||
final String key;
|
final String key;
|
||||||
@ -725,50 +666,34 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
final boolean isExtAudioEnabled = preferences.getBoolean(
|
final boolean isExtAudioEnabled = preferences.getBoolean(
|
||||||
getString(R.string.use_external_audio_player_key), false);
|
getString(R.string.use_external_audio_player_key), false);
|
||||||
|
|
||||||
PlayQueue playQueue;
|
final PlayQueue playQueue;
|
||||||
final String playerChoice = choice.playerChoice;
|
|
||||||
|
|
||||||
if (info instanceof StreamInfo) {
|
if (info instanceof StreamInfo) {
|
||||||
if (playerChoice.equals(backgroundPlayerKey) && isExtAudioEnabled) {
|
if (choice.playerChoice.equals(backgroundPlayerKey) && isExtAudioEnabled) {
|
||||||
NavigationHelper.playOnExternalAudioPlayer(this, (StreamInfo) info);
|
NavigationHelper.playOnExternalAudioPlayer(this, (StreamInfo) info);
|
||||||
|
return;
|
||||||
} else if (playerChoice.equals(videoPlayerKey) && isExtVideoEnabled) {
|
} else if (choice.playerChoice.equals(videoPlayerKey) && isExtVideoEnabled) {
|
||||||
NavigationHelper.playOnExternalVideoPlayer(this, (StreamInfo) info);
|
NavigationHelper.playOnExternalVideoPlayer(this, (StreamInfo) info);
|
||||||
|
return;
|
||||||
} else {
|
}
|
||||||
playQueue = new SinglePlayQueue((StreamInfo) info);
|
playQueue = new SinglePlayQueue((StreamInfo) info);
|
||||||
|
} else if (info instanceof ChannelInfo) {
|
||||||
if (playerChoice.equals(videoPlayerKey)) {
|
playQueue = new ChannelPlayQueue((ChannelInfo) info);
|
||||||
openMainPlayer(playQueue, choice);
|
} else if (info instanceof PlaylistInfo) {
|
||||||
} else if (playerChoice.equals(backgroundPlayerKey)) {
|
playQueue = new PlaylistPlayQueue((PlaylistInfo) info);
|
||||||
NavigationHelper.enqueueOnBackgroundPlayer(this, playQueue, true);
|
} else {
|
||||||
} else if (playerChoice.equals(popupPlayerKey)) {
|
return;
|
||||||
NavigationHelper.enqueueOnPopupPlayer(this, playQueue, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info instanceof ChannelInfo || info instanceof PlaylistInfo) {
|
if (choice.playerChoice.equals(videoPlayerKey)) {
|
||||||
playQueue = info instanceof ChannelInfo
|
NavigationHelper.playOnMainPlayer(this, playQueue, false);
|
||||||
? new ChannelPlayQueue((ChannelInfo) info)
|
} else if (choice.playerChoice.equals(backgroundPlayerKey)) {
|
||||||
: new PlaylistPlayQueue((PlaylistInfo) info);
|
|
||||||
|
|
||||||
if (playerChoice.equals(videoPlayerKey)) {
|
|
||||||
openMainPlayer(playQueue, choice);
|
|
||||||
} else if (playerChoice.equals(backgroundPlayerKey)) {
|
|
||||||
NavigationHelper.playOnBackgroundPlayer(this, playQueue, true);
|
NavigationHelper.playOnBackgroundPlayer(this, playQueue, true);
|
||||||
} else if (playerChoice.equals(popupPlayerKey)) {
|
} else if (choice.playerChoice.equals(popupPlayerKey)) {
|
||||||
NavigationHelper.playOnPopupPlayer(this, playQueue, true);
|
NavigationHelper.playOnPopupPlayer(this, playQueue, true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openMainPlayer(final PlayQueue playQueue, final Choice choice) {
|
|
||||||
NavigationHelper.playOnMainPlayer(this, playQueue, choice.linkType,
|
|
||||||
choice.url, "", true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
@ -110,6 +110,7 @@ import org.schabi.newpipe.views.LargeTextMovementMethod;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
@ -128,7 +129,7 @@ import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfi
|
|||||||
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
public class VideoDetailFragment
|
public final class VideoDetailFragment
|
||||||
extends BaseStateFragment<StreamInfo>
|
extends BaseStateFragment<StreamInfo>
|
||||||
implements BackPressable,
|
implements BackPressable,
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener,
|
SharedPreferences.OnSharedPreferenceChangeListener,
|
||||||
@ -136,7 +137,7 @@ public class VideoDetailFragment
|
|||||||
View.OnLongClickListener,
|
View.OnLongClickListener,
|
||||||
PlayerServiceExtendedEventListener,
|
PlayerServiceExtendedEventListener,
|
||||||
OnKeyDownListener {
|
OnKeyDownListener {
|
||||||
public static final String AUTO_PLAY = "auto_play";
|
public static final String KEY_SWITCHING_PLAYERS = "switching_players";
|
||||||
|
|
||||||
private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1;
|
private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1;
|
||||||
private static final int COMMENTS_UPDATE_FLAG = 0x2;
|
private static final int COMMENTS_UPDATE_FLAG = 0x2;
|
||||||
@ -167,19 +168,23 @@ public class VideoDetailFragment
|
|||||||
@State
|
@State
|
||||||
protected int serviceId = Constants.NO_SERVICE_ID;
|
protected int serviceId = Constants.NO_SERVICE_ID;
|
||||||
@State
|
@State
|
||||||
protected String name;
|
@NonNull
|
||||||
|
protected String title = "";
|
||||||
@State
|
@State
|
||||||
protected String url;
|
@Nullable
|
||||||
protected static PlayQueue playQueue;
|
protected String url = null;
|
||||||
|
@Nullable
|
||||||
|
protected PlayQueue playQueue = null;
|
||||||
@State
|
@State
|
||||||
int bottomSheetState = BottomSheetBehavior.STATE_EXPANDED;
|
int bottomSheetState = BottomSheetBehavior.STATE_EXPANDED;
|
||||||
@State
|
@State
|
||||||
protected boolean autoPlayEnabled = true;
|
protected boolean autoPlayEnabled = true;
|
||||||
|
|
||||||
private static StreamInfo currentInfo;
|
@Nullable
|
||||||
|
private StreamInfo currentInfo = null;
|
||||||
private Disposable currentWorker;
|
private Disposable currentWorker;
|
||||||
@NonNull
|
@NonNull
|
||||||
private CompositeDisposable disposables = new CompositeDisposable();
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
@Nullable
|
@Nullable
|
||||||
private Disposable positionSubscriber = null;
|
private Disposable positionSubscriber = null;
|
||||||
|
|
||||||
@ -284,6 +289,7 @@ public class VideoDetailFragment
|
|||||||
|| (currentInfo != null
|
|| (currentInfo != null
|
||||||
&& isAutoplayEnabled()
|
&& isAutoplayEnabled()
|
||||||
&& player.getParentActivity() == null)) {
|
&& player.getParentActivity() == null)) {
|
||||||
|
autoPlayEnabled = true; // forcefully start playing
|
||||||
openVideoPlayer();
|
openVideoPlayer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,8 +304,10 @@ public class VideoDetailFragment
|
|||||||
|
|
||||||
/*////////////////////////////////////////////////////////////////////////*/
|
/*////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public static VideoDetailFragment getInstance(final int serviceId, final String videoUrl,
|
public static VideoDetailFragment getInstance(final int serviceId,
|
||||||
final String name, final PlayQueue queue) {
|
@Nullable final String videoUrl,
|
||||||
|
@NonNull final String name,
|
||||||
|
@Nullable final PlayQueue queue) {
|
||||||
final VideoDetailFragment instance = new VideoDetailFragment();
|
final VideoDetailFragment instance = new VideoDetailFragment();
|
||||||
instance.setInitialData(serviceId, videoUrl, name, queue);
|
instance.setInitialData(serviceId, videoUrl, name, queue);
|
||||||
return instance;
|
return instance;
|
||||||
@ -444,8 +452,8 @@ public class VideoDetailFragment
|
|||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case ReCaptchaActivity.RECAPTCHA_REQUEST:
|
case ReCaptchaActivity.RECAPTCHA_REQUEST:
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
NavigationHelper
|
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
|
||||||
.openVideoDetailFragment(getFM(), serviceId, url, name);
|
serviceId, url, title, null, false);
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "ReCaptcha failed");
|
Log.e(TAG, "ReCaptcha failed");
|
||||||
}
|
}
|
||||||
@ -514,6 +522,7 @@ public class VideoDetailFragment
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case R.id.detail_thumbnail_root_layout:
|
case R.id.detail_thumbnail_root_layout:
|
||||||
|
autoPlayEnabled = true; // forcefully start playing
|
||||||
openVideoPlayer();
|
openVideoPlayer();
|
||||||
break;
|
break;
|
||||||
case R.id.detail_title_root_layout:
|
case R.id.detail_title_root_layout:
|
||||||
@ -530,6 +539,7 @@ public class VideoDetailFragment
|
|||||||
player.hideControls(0, 0);
|
player.hideControls(0, 0);
|
||||||
showSystemUi();
|
showSystemUi();
|
||||||
} else {
|
} else {
|
||||||
|
autoPlayEnabled = true; // forcefully start playing
|
||||||
openVideoPlayer();
|
openVideoPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -791,7 +801,7 @@ public class VideoDetailFragment
|
|||||||
player.onPause();
|
player.onPause();
|
||||||
}
|
}
|
||||||
restoreDefaultOrientation();
|
restoreDefaultOrientation();
|
||||||
setAutoplay(false);
|
setAutoPlay(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -819,14 +829,11 @@ public class VideoDetailFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupFromHistoryItem(final StackItem item) {
|
private void setupFromHistoryItem(final StackItem item) {
|
||||||
setAutoplay(false);
|
setAutoPlay(false);
|
||||||
hideMainPlayer();
|
hideMainPlayer();
|
||||||
|
|
||||||
setInitialData(
|
setInitialData(item.getServiceId(), item.getUrl(),
|
||||||
item.getServiceId(),
|
item.getTitle() == null ? "" : item.getTitle(), item.getPlayQueue());
|
||||||
item.getUrl(),
|
|
||||||
!TextUtils.isEmpty(item.getTitle()) ? item.getTitle() : "",
|
|
||||||
item.getPlayQueue());
|
|
||||||
startLoading(false);
|
startLoading(false);
|
||||||
|
|
||||||
// Maybe an item was deleted in background activity
|
// Maybe an item was deleted in background activity
|
||||||
@ -860,18 +867,17 @@ public class VideoDetailFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectAndLoadVideo(final int sid, final String videoUrl, final String title,
|
public void selectAndLoadVideo(final int newServiceId,
|
||||||
final PlayQueue queue) {
|
@Nullable final String newUrl,
|
||||||
// Situation when user switches from players to main player.
|
@NonNull final String newTitle,
|
||||||
// All needed data is here, we can start watching
|
@Nullable final PlayQueue newQueue) {
|
||||||
if (this.playQueue != null && this.playQueue.equals(queue)) {
|
if (player != null && newQueue != null && playQueue != null
|
||||||
openVideoPlayer();
|
&& !Objects.equals(newQueue.getItem(), playQueue.getItem())) {
|
||||||
return;
|
// Preloading can be disabled since playback is surely being replaced.
|
||||||
}
|
|
||||||
setInitialData(sid, videoUrl, title, queue);
|
|
||||||
if (player != null) {
|
|
||||||
player.disablePreloadingOfCurrentTrack();
|
player.disablePreloadingOfCurrentTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setInitialData(newServiceId, newUrl, newTitle, newQueue);
|
||||||
startLoading(false, true);
|
startLoading(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -956,7 +962,7 @@ public class VideoDetailFragment
|
|||||||
playQueue = new SinglePlayQueue(result);
|
playQueue = new SinglePlayQueue(result);
|
||||||
}
|
}
|
||||||
if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(playQueue)) {
|
if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(playQueue)) {
|
||||||
stack.push(new StackItem(serviceId, url, name, playQueue));
|
stack.push(new StackItem(serviceId, url, title, playQueue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isAutoplayEnabled()) {
|
if (isAutoplayEnabled()) {
|
||||||
@ -977,7 +983,7 @@ public class VideoDetailFragment
|
|||||||
|
|
||||||
if (shouldShowComments()) {
|
if (shouldShowComments()) {
|
||||||
pageAdapter.addFragment(
|
pageAdapter.addFragment(
|
||||||
CommentsFragment.getInstance(serviceId, url, name), COMMENTS_TAB_TAG);
|
CommentsFragment.getInstance(serviceId, url, title), COMMENTS_TAB_TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showRelatedStreams && null == relatedStreamsLayout) {
|
if (showRelatedStreams && null == relatedStreamsLayout) {
|
||||||
@ -1068,7 +1074,7 @@ public class VideoDetailFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openVideoPlayer() {
|
public void openVideoPlayer() {
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(activity)
|
if (PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
.getBoolean(this.getString(R.string.use_external_video_player_key), false)) {
|
.getBoolean(this.getString(R.string.use_external_video_player_key), false)) {
|
||||||
showExternalPlaybackDialog();
|
showExternalPlaybackDialog();
|
||||||
@ -1094,7 +1100,7 @@ public class VideoDetailFragment
|
|||||||
|
|
||||||
private void openMainPlayer() {
|
private void openMainPlayer() {
|
||||||
if (playerService == null) {
|
if (playerService == null) {
|
||||||
PlayerHolder.startService(App.getApp(), true, this);
|
PlayerHolder.startService(App.getApp(), autoPlayEnabled, this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currentInfo == null) {
|
if (currentInfo == null) {
|
||||||
@ -1105,11 +1111,13 @@ public class VideoDetailFragment
|
|||||||
|
|
||||||
// Video view can have elements visible from popup,
|
// Video view can have elements visible from popup,
|
||||||
// We hide it here but once it ready the view will be shown in handleIntent()
|
// We hide it here but once it ready the view will be shown in handleIntent()
|
||||||
|
if (playerService.getView() != null) {
|
||||||
playerService.getView().setVisibility(View.GONE);
|
playerService.getView().setVisibility(View.GONE);
|
||||||
|
}
|
||||||
addVideoPlayerView();
|
addVideoPlayerView();
|
||||||
|
|
||||||
final Intent playerIntent = NavigationHelper
|
final Intent playerIntent = NavigationHelper
|
||||||
.getPlayerIntent(requireContext(), MainPlayer.class, queue, null, true);
|
.getPlayerIntent(requireContext(), MainPlayer.class, queue, true, autoPlayEnabled);
|
||||||
activity.startService(playerIntent);
|
activity.startService(playerIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1143,8 +1151,8 @@ public class VideoDetailFragment
|
|||||||
// Utils
|
// Utils
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public void setAutoplay(final boolean autoplay) {
|
public void setAutoPlay(final boolean autoPlay) {
|
||||||
this.autoPlayEnabled = autoplay;
|
this.autoPlayEnabled = autoPlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startOnExternalPlayer(@NonNull final Context context,
|
private void startOnExternalPlayer(@NonNull final Context context,
|
||||||
@ -1166,7 +1174,7 @@ public class VideoDetailFragment
|
|||||||
.getBoolean(getString(R.string.use_external_video_player_key), false);
|
.getBoolean(getString(R.string.use_external_video_player_key), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method overrides default behaviour when setAutoplay() is called.
|
// This method overrides default behaviour when setAutoPlay() is called.
|
||||||
// Don't auto play if the user selected an external player or disabled it in settings
|
// Don't auto play if the user selected an external player or disabled it in settings
|
||||||
private boolean isAutoplayEnabled() {
|
private boolean isAutoplayEnabled() {
|
||||||
return autoPlayEnabled
|
return autoPlayEnabled
|
||||||
@ -1302,12 +1310,14 @@ public class VideoDetailFragment
|
|||||||
contentRootLayoutHiding.setVisibility(View.VISIBLE);
|
contentRootLayoutHiding.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setInitialData(final int sid, final String u, final String title,
|
protected void setInitialData(final int newServiceId,
|
||||||
final PlayQueue queue) {
|
@Nullable final String newUrl,
|
||||||
this.serviceId = sid;
|
@NonNull final String newTitle,
|
||||||
this.url = u;
|
@Nullable final PlayQueue newPlayQueue) {
|
||||||
this.name = !TextUtils.isEmpty(title) ? title : "";
|
this.serviceId = newServiceId;
|
||||||
this.playQueue = queue;
|
this.url = newUrl;
|
||||||
|
this.title = newTitle;
|
||||||
|
this.playQueue = newPlayQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setErrorImage(final int imageResource) {
|
private void setErrorImage(final int imageResource) {
|
||||||
@ -1400,7 +1410,7 @@ public class VideoDetailFragment
|
|||||||
animateView(detailPositionView, false, 100);
|
animateView(detailPositionView, false, 100);
|
||||||
animateView(positionView, false, 50);
|
animateView(positionView, false, 50);
|
||||||
|
|
||||||
videoTitleTextView.setText(name != null ? name : "");
|
videoTitleTextView.setText(title);
|
||||||
videoTitleTextView.setMaxLines(1);
|
videoTitleTextView.setMaxLines(1);
|
||||||
animateView(videoTitleTextView, true, 0);
|
animateView(videoTitleTextView, true, 0);
|
||||||
|
|
||||||
@ -1445,7 +1455,7 @@ public class VideoDetailFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
animateView(thumbnailPlayButton, true, 200);
|
animateView(thumbnailPlayButton, true, 200);
|
||||||
videoTitleTextView.setText(name);
|
videoTitleTextView.setText(title);
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(info.getSubChannelName())) {
|
if (!TextUtils.isEmpty(info.getSubChannelName())) {
|
||||||
displayBothUploaderAndSubChannel(info);
|
displayBothUploaderAndSubChannel(info);
|
||||||
@ -1738,7 +1748,7 @@ public class VideoDetailFragment
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "onQueueUpdate() called with: serviceId = ["
|
Log.d(TAG, "onQueueUpdate() called with: serviceId = ["
|
||||||
+ serviceId + "], videoUrl = [" + url + "], name = ["
|
+ serviceId + "], videoUrl = [" + url + "], name = ["
|
||||||
+ name + "], playQueue = [" + playQueue + "]");
|
+ title + "], playQueue = [" + playQueue + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should be the only place where we push data to stack.
|
// This should be the only place where we push data to stack.
|
||||||
@ -1823,7 +1833,7 @@ public class VideoDetailFragment
|
|||||||
|
|
||||||
currentInfo = info;
|
currentInfo = info;
|
||||||
setInitialData(info.getServiceId(), info.getUrl(), info.getName(), queue);
|
setInitialData(info.getServiceId(), info.getUrl(), info.getName(), queue);
|
||||||
setAutoplay(false);
|
setAutoPlay(false);
|
||||||
// Delay execution just because it freezes the main thread, and while playing
|
// Delay execution just because it freezes the main thread, and while playing
|
||||||
// next/previous video you see visual glitches
|
// next/previous video you see visual glitches
|
||||||
// (when non-vertical video goes after vertical video)
|
// (when non-vertical video goes after vertical video)
|
||||||
@ -2037,7 +2047,7 @@ public class VideoDetailFragment
|
|||||||
private void checkLandscape() {
|
private void checkLandscape() {
|
||||||
if ((!player.isPlaying() && player.getPlayQueue() != playQueue)
|
if ((!player.isPlaying() && player.getPlayQueue() != playQueue)
|
||||||
|| player.getPlayQueue() == null) {
|
|| player.getPlayQueue() == null) {
|
||||||
setAutoplay(true);
|
setAutoPlay(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
player.checkLandscape();
|
player.checkLandscape();
|
||||||
@ -2287,10 +2297,10 @@ public class VideoDetailFragment
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOverlayData(@Nullable final String title,
|
private void updateOverlayData(@Nullable final String overlayTitle,
|
||||||
@Nullable final String uploader,
|
@Nullable final String uploader,
|
||||||
@Nullable final String thumbnailUrl) {
|
@Nullable final String thumbnailUrl) {
|
||||||
overlayTitleTextView.setText(TextUtils.isEmpty(title) ? "" : title);
|
overlayTitleTextView.setText(TextUtils.isEmpty(overlayTitle) ? "" : overlayTitle);
|
||||||
overlayChannelTextView.setText(TextUtils.isEmpty(uploader) ? "" : uploader);
|
overlayChannelTextView.setText(TextUtils.isEmpty(uploader) ? "" : uploader);
|
||||||
overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
|
overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
|
||||||
if (!TextUtils.isEmpty(thumbnailUrl)) {
|
if (!TextUtils.isEmpty(thumbnailUrl)) {
|
||||||
|
@ -321,8 +321,9 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
|||||||
|
|
||||||
private void onStreamSelected(final StreamInfoItem selectedItem) {
|
private void onStreamSelected(final StreamInfoItem selectedItem) {
|
||||||
onItemSelected(selectedItem);
|
onItemSelected(selectedItem);
|
||||||
NavigationHelper.openVideoDetailFragment(getFM(),
|
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
|
||||||
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
|
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName(),
|
||||||
|
null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onScrollToBottom() {
|
protected void onScrollToBottom() {
|
||||||
|
@ -517,7 +517,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
|
|||||||
monitorSubscription(result);
|
monitorSubscription(result);
|
||||||
|
|
||||||
headerPlayAllButton.setOnClickListener(view -> NavigationHelper
|
headerPlayAllButton.setOnClickListener(view -> NavigationHelper
|
||||||
.playOnMainPlayer(activity, getPlayQueue(), true));
|
.playOnMainPlayer(activity, getPlayQueue()));
|
||||||
headerPopupButton.setOnClickListener(view -> NavigationHelper
|
headerPopupButton.setOnClickListener(view -> NavigationHelper
|
||||||
.playOnPopupPlayer(activity, getPlayQueue(), false));
|
.playOnPopupPlayer(activity, getPlayQueue(), false));
|
||||||
headerBackgroundButton.setOnClickListener(view -> NavigationHelper
|
headerBackgroundButton.setOnClickListener(view -> NavigationHelper
|
||||||
|
@ -319,7 +319,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
|||||||
.subscribe(getPlaylistBookmarkSubscriber());
|
.subscribe(getPlaylistBookmarkSubscriber());
|
||||||
|
|
||||||
headerPlayAllButton.setOnClickListener(view ->
|
headerPlayAllButton.setOnClickListener(view ->
|
||||||
NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), true));
|
NavigationHelper.playOnMainPlayer(activity, getPlayQueue()));
|
||||||
headerPopupButton.setOnClickListener(view ->
|
headerPopupButton.setOnClickListener(view ->
|
||||||
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false));
|
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false));
|
||||||
headerBackgroundButton.setOnClickListener(view ->
|
headerBackgroundButton.setOnClickListener(view ->
|
||||||
|
@ -25,6 +25,7 @@ import org.reactivestreams.Subscription;
|
|||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
||||||
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||||
@ -149,11 +150,10 @@ public class StatisticsPlaylistFragment
|
|||||||
@Override
|
@Override
|
||||||
public void selected(final LocalItem selectedItem) {
|
public void selected(final LocalItem selectedItem) {
|
||||||
if (selectedItem instanceof StreamStatisticsEntry) {
|
if (selectedItem instanceof StreamStatisticsEntry) {
|
||||||
final StreamStatisticsEntry item = (StreamStatisticsEntry) selectedItem;
|
final StreamEntity item =
|
||||||
NavigationHelper.openVideoDetailFragment(getFM(),
|
((StreamStatisticsEntry) selectedItem).getStreamEntity();
|
||||||
item.getStreamEntity().getServiceId(),
|
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
|
||||||
item.getStreamEntity().getUrl(),
|
item.getServiceId(), item.getUrl(), item.getTitle(), null, false);
|
||||||
item.getStreamEntity().getTitle());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,7 +325,7 @@ public class StatisticsPlaylistFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
headerPlayAllButton.setOnClickListener(view ->
|
headerPlayAllButton.setOnClickListener(view ->
|
||||||
NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), true));
|
NavigationHelper.playOnMainPlayer(activity, getPlayQueue()));
|
||||||
headerPopupButton.setOnClickListener(view ->
|
headerPopupButton.setOnClickListener(view ->
|
||||||
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false));
|
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false));
|
||||||
headerBackgroundButton.setOnClickListener(view ->
|
headerBackgroundButton.setOnClickListener(view ->
|
||||||
|
@ -30,6 +30,7 @@ import org.schabi.newpipe.R;
|
|||||||
import org.schabi.newpipe.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.database.history.model.StreamHistoryEntry;
|
import org.schabi.newpipe.database.history.model.StreamHistoryEntry;
|
||||||
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
|
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
|
||||||
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
|
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
@ -178,10 +179,10 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||||||
@Override
|
@Override
|
||||||
public void selected(final LocalItem selectedItem) {
|
public void selected(final LocalItem selectedItem) {
|
||||||
if (selectedItem instanceof PlaylistStreamEntry) {
|
if (selectedItem instanceof PlaylistStreamEntry) {
|
||||||
final PlaylistStreamEntry item = (PlaylistStreamEntry) selectedItem;
|
final StreamEntity item =
|
||||||
NavigationHelper.openVideoDetailFragment(getFM(),
|
((PlaylistStreamEntry) selectedItem).getStreamEntity();
|
||||||
item.getStreamEntity().getServiceId(), item.getStreamEntity().getUrl(),
|
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
|
||||||
item.getStreamEntity().getTitle());
|
item.getServiceId(), item.getUrl(), item.getTitle(), null, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,7 +495,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||||||
setVideoCount(itemListAdapter.getItemsList().size());
|
setVideoCount(itemListAdapter.getItemsList().size());
|
||||||
|
|
||||||
headerPlayAllButton.setOnClickListener(view ->
|
headerPlayAllButton.setOnClickListener(view ->
|
||||||
NavigationHelper.playOnMainPlayer(activity, getPlayQueue(), true));
|
NavigationHelper.playOnMainPlayer(activity, getPlayQueue()));
|
||||||
headerPopupButton.setOnClickListener(view ->
|
headerPopupButton.setOnClickListener(view ->
|
||||||
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false));
|
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue(), false));
|
||||||
headerBackgroundButton.setOnClickListener(view ->
|
headerBackgroundButton.setOnClickListener(view ->
|
||||||
|
@ -2,11 +2,8 @@ package org.schabi.newpipe.player;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
|
||||||
|
|
||||||
public final class BackgroundPlayerActivity extends ServicePlayerActivity {
|
public final class BackgroundPlayerActivity extends ServicePlayerActivity {
|
||||||
|
|
||||||
@ -46,31 +43,6 @@ public final class BackgroundPlayerActivity extends ServicePlayerActivity {
|
|||||||
return R.menu.menu_play_queue_bg;
|
return R.menu.menu_play_queue_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPlayerOptionSelected(final MenuItem item) {
|
|
||||||
if (item.getItemId() == R.id.action_switch_popup) {
|
|
||||||
|
|
||||||
if (!PermissionHelper.isPopupEnabled(this)) {
|
|
||||||
PermissionHelper.showPopupEnablementToast(this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.player.setRecovery();
|
|
||||||
NavigationHelper.playOnPopupPlayer(
|
|
||||||
getApplicationContext(), player.playQueue, this.player.isPlaying());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.getItemId() == R.id.action_switch_background) {
|
|
||||||
this.player.setRecovery();
|
|
||||||
NavigationHelper.playOnBackgroundPlayer(
|
|
||||||
getApplicationContext(), player.playQueue, this.player.isPlaying());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setupMenu(final Menu menu) {
|
public void setupMenu(final Menu menu) {
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
|
@ -125,7 +125,7 @@ public abstract class BasePlayer implements
|
|||||||
@NonNull
|
@NonNull
|
||||||
public static final String RESUME_PLAYBACK = "resume_playback";
|
public static final String RESUME_PLAYBACK = "resume_playback";
|
||||||
@NonNull
|
@NonNull
|
||||||
public static final String START_PAUSED = "start_paused";
|
public static final String PLAY_WHEN_READY = "play_when_ready";
|
||||||
@NonNull
|
@NonNull
|
||||||
public static final String SELECT_ON_APPEND = "select_on_append";
|
public static final String SELECT_ON_APPEND = "select_on_append";
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -224,7 +224,7 @@ public abstract class BasePlayer implements
|
|||||||
this.dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter);
|
this.dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter);
|
||||||
|
|
||||||
final TrackSelection.Factory trackSelectionFactory = PlayerHelper
|
final TrackSelection.Factory trackSelectionFactory = PlayerHelper
|
||||||
.getQualitySelector(context);
|
.getQualitySelector();
|
||||||
this.trackSelector = new CustomTrackSelector(context, trackSelectionFactory);
|
this.trackSelector = new CustomTrackSelector(context, trackSelectionFactory);
|
||||||
|
|
||||||
this.loadControl = new LoadController();
|
this.loadControl = new LoadController();
|
||||||
@ -302,6 +302,7 @@ public abstract class BasePlayer implements
|
|||||||
final boolean samePlayQueue = playQueue != null && playQueue.equals(queue);
|
final boolean samePlayQueue = playQueue != null && playQueue.equals(queue);
|
||||||
|
|
||||||
final int repeatMode = intent.getIntExtra(REPEAT_MODE, getRepeatMode());
|
final int repeatMode = intent.getIntExtra(REPEAT_MODE, getRepeatMode());
|
||||||
|
final boolean playWhenReady = intent.getBooleanExtra(PLAY_WHEN_READY, true);
|
||||||
final boolean isMuted = intent
|
final boolean isMuted = intent
|
||||||
.getBooleanExtra(IS_MUTED, simpleExoPlayer != null && isMuted());
|
.getBooleanExtra(IS_MUTED, simpleExoPlayer != null && isMuted());
|
||||||
|
|
||||||
@ -327,16 +328,20 @@ public abstract class BasePlayer implements
|
|||||||
simpleExoPlayer.retry();
|
simpleExoPlayer.retry();
|
||||||
}
|
}
|
||||||
simpleExoPlayer.seekTo(playQueue.getIndex(), queue.getItem().getRecoveryPosition());
|
simpleExoPlayer.seekTo(playQueue.getIndex(), queue.getItem().getRecoveryPosition());
|
||||||
return;
|
simpleExoPlayer.setPlayWhenReady(playWhenReady);
|
||||||
|
|
||||||
} else if (samePlayQueue && !playQueue.isDisposed() && simpleExoPlayer != null) {
|
} else if (simpleExoPlayer != null
|
||||||
|
&& samePlayQueue
|
||||||
|
&& playQueue != null
|
||||||
|
&& !playQueue.isDisposed()) {
|
||||||
// Do not re-init the same PlayQueue. Save time
|
// Do not re-init the same PlayQueue. Save time
|
||||||
// Player can have state = IDLE when playback is stopped or failed
|
// Player can have state = IDLE when playback is stopped or failed
|
||||||
// and we should retry() in this case
|
// and we should retry() in this case
|
||||||
if (simpleExoPlayer.getPlaybackState() == Player.STATE_IDLE) {
|
if (simpleExoPlayer.getPlaybackState() == Player.STATE_IDLE) {
|
||||||
simpleExoPlayer.retry();
|
simpleExoPlayer.retry();
|
||||||
}
|
}
|
||||||
return;
|
simpleExoPlayer.setPlayWhenReady(playWhenReady);
|
||||||
|
|
||||||
} else if (intent.getBooleanExtra(RESUME_PLAYBACK, false)
|
} else if (intent.getBooleanExtra(RESUME_PLAYBACK, false)
|
||||||
&& isPlaybackResumeEnabled()
|
&& isPlaybackResumeEnabled()
|
||||||
&& !samePlayQueue) {
|
&& !samePlayQueue) {
|
||||||
@ -351,7 +356,7 @@ public abstract class BasePlayer implements
|
|||||||
state -> {
|
state -> {
|
||||||
queue.setRecovery(queue.getIndex(), state.getProgressTime());
|
queue.setRecovery(queue.getIndex(), state.getProgressTime());
|
||||||
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch,
|
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch,
|
||||||
playbackSkipSilence, true, isMuted);
|
playbackSkipSilence, playWhenReady, isMuted);
|
||||||
},
|
},
|
||||||
error -> {
|
error -> {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -359,24 +364,22 @@ public abstract class BasePlayer implements
|
|||||||
}
|
}
|
||||||
// In case any error we can start playback without history
|
// In case any error we can start playback without history
|
||||||
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch,
|
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch,
|
||||||
playbackSkipSilence, true, isMuted);
|
playbackSkipSilence, playWhenReady, isMuted);
|
||||||
},
|
},
|
||||||
() -> {
|
() -> {
|
||||||
// Completed but not found in history
|
// Completed but not found in history
|
||||||
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch,
|
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch,
|
||||||
playbackSkipSilence, true, isMuted);
|
playbackSkipSilence, playWhenReady, isMuted);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
databaseUpdateReactor.add(stateLoader);
|
databaseUpdateReactor.add(stateLoader);
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// Good to go...
|
// Good to go...
|
||||||
// In a case of equal PlayQueues we can re-init old one but only when it is disposed
|
// In a case of equal PlayQueues we can re-init old one but only when it is disposed
|
||||||
initPlayback(samePlayQueue ? playQueue : queue, repeatMode,
|
initPlayback(samePlayQueue ? playQueue : queue, repeatMode, playbackSpeed,
|
||||||
playbackSpeed, playbackPitch, playbackSkipSilence,
|
playbackPitch, playbackSkipSilence, playWhenReady, isMuted);
|
||||||
!intent.getBooleanExtra(START_PAUSED, false),
|
}
|
||||||
isMuted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlaybackParameters retrievePlaybackParametersFromPreferences() {
|
private PlaybackParameters retrievePlaybackParametersFromPreferences() {
|
||||||
|
@ -30,6 +30,7 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
@ -231,6 +232,7 @@ public final class MainPlayer extends Service {
|
|||||||
return metrics.heightPixels < metrics.widthPixels;
|
return metrics.heightPixels < metrics.widthPixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public View getView() {
|
public View getView() {
|
||||||
if (playerImpl == null) {
|
if (playerImpl == null) {
|
||||||
return null;
|
return null;
|
||||||
@ -240,7 +242,7 @@ public final class MainPlayer extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeViewFromParent() {
|
public void removeViewFromParent() {
|
||||||
if (getView().getParent() != null) {
|
if (getView() != null && getView().getParent() != null) {
|
||||||
if (playerImpl.getParentActivity() != null) {
|
if (playerImpl.getParentActivity() != null) {
|
||||||
// This means view was added to fragment
|
// This means view was added to fragment
|
||||||
final ViewGroup parent = (ViewGroup) getView().getParent();
|
final ViewGroup parent = (ViewGroup) getView().getParent();
|
||||||
|
@ -27,9 +27,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
|
|
||||||
import org.schabi.newpipe.MainActivity;
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
||||||
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
||||||
@ -42,9 +40,9 @@ import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
|||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItemBuilder;
|
import org.schabi.newpipe.player.playqueue.PlayQueueItemBuilder;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItemHolder;
|
import org.schabi.newpipe.player.playqueue.PlayQueueItemHolder;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItemTouchCallback;
|
import org.schabi.newpipe.player.playqueue.PlayQueueItemTouchCallback;
|
||||||
import org.schabi.newpipe.util.Constants;
|
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
|
import org.schabi.newpipe.util.PermissionHelper;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -113,9 +111,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
|||||||
|
|
||||||
public abstract int getPlayerOptionMenuResource();
|
public abstract int getPlayerOptionMenuResource();
|
||||||
|
|
||||||
public abstract boolean onPlayerOptionSelected(MenuItem item);
|
|
||||||
|
|
||||||
public abstract void setupMenu(Menu m);
|
public abstract void setupMenu(Menu m);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Activity Lifecycle
|
// Activity Lifecycle
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
@ -187,12 +184,22 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
|||||||
return true;
|
return true;
|
||||||
case R.id.action_switch_main:
|
case R.id.action_switch_main:
|
||||||
this.player.setRecovery();
|
this.player.setRecovery();
|
||||||
getApplicationContext().startActivity(
|
NavigationHelper.playOnMainPlayer(this, player.getPlayQueue(), true);
|
||||||
getSwitchIntent(MainActivity.class, MainPlayer.PlayerType.VIDEO)
|
return true;
|
||||||
.putExtra(BasePlayer.START_PAUSED, !this.player.isPlaying()));
|
case R.id.action_switch_popup:
|
||||||
|
if (PermissionHelper.isPopupEnabled(this)) {
|
||||||
|
this.player.setRecovery();
|
||||||
|
NavigationHelper.playOnPopupPlayer(this, player.playQueue, true);
|
||||||
|
} else {
|
||||||
|
PermissionHelper.showPopupEnablementToast(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case R.id.action_switch_background:
|
||||||
|
this.player.setRecovery();
|
||||||
|
NavigationHelper.playOnBackgroundPlayer(this, player.playQueue, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return onPlayerOptionSelected(item) || super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -201,24 +208,6 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
|||||||
unbind();
|
unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Intent getSwitchIntent(final Class clazz, final MainPlayer.PlayerType playerType) {
|
|
||||||
return NavigationHelper.getPlayerIntent(getApplicationContext(), clazz,
|
|
||||||
this.player.getPlayQueue(), this.player.getRepeatMode(),
|
|
||||||
this.player.getPlaybackSpeed(), this.player.getPlaybackPitch(),
|
|
||||||
this.player.getPlaybackSkipSilence(),
|
|
||||||
null,
|
|
||||||
true,
|
|
||||||
!this.player.isPlaying(),
|
|
||||||
this.player.isMuted())
|
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
.putExtra(Constants.KEY_LINK_TYPE, StreamingService.LinkType.STREAM)
|
|
||||||
.putExtra(Constants.KEY_URL, this.player.getVideoUrl())
|
|
||||||
.putExtra(Constants.KEY_TITLE, this.player.getVideoTitle())
|
|
||||||
.putExtra(Constants.KEY_SERVICE_ID,
|
|
||||||
this.player.getCurrentMetadata().getMetadata().getServiceId())
|
|
||||||
.putExtra(VideoPlayer.PLAYER_TYPE, playerType);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Service Connection
|
// Service Connection
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
@ -367,7 +356,9 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
|||||||
final MenuItem detail = popupMenu.getMenu().add(RECYCLER_ITEM_POPUP_MENU_GROUP_ID, 1,
|
final MenuItem detail = popupMenu.getMenu().add(RECYCLER_ITEM_POPUP_MENU_GROUP_ID, 1,
|
||||||
Menu.NONE, R.string.play_queue_stream_detail);
|
Menu.NONE, R.string.play_queue_stream_detail);
|
||||||
detail.setOnMenuItemClickListener(menuItem -> {
|
detail.setOnMenuItemClickListener(menuItem -> {
|
||||||
onOpenDetail(item.getServiceId(), item.getUrl(), item.getTitle());
|
// playQueue is null since we don't want any queue change
|
||||||
|
NavigationHelper.openVideoDetail(this, item.getServiceId(), item.getUrl(),
|
||||||
|
item.getTitle(), null, false);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -454,11 +445,6 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onOpenDetail(final int serviceId, final String videoUrl,
|
|
||||||
final String videoTitle) {
|
|
||||||
NavigationHelper.openVideoDetail(this, serviceId, videoUrl, videoTitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void scrollToSelected() {
|
private void scrollToSelected() {
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -76,9 +76,7 @@ import com.google.android.exoplayer2.ui.SubtitleView;
|
|||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||||
|
|
||||||
import org.schabi.newpipe.MainActivity;
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
||||||
@ -97,7 +95,6 @@ import org.schabi.newpipe.player.resolver.AudioPlaybackResolver;
|
|||||||
import org.schabi.newpipe.player.resolver.MediaSourceTag;
|
import org.schabi.newpipe.player.resolver.MediaSourceTag;
|
||||||
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
|
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
|
||||||
import org.schabi.newpipe.util.AnimationUtils;
|
import org.schabi.newpipe.util.AnimationUtils;
|
||||||
import org.schabi.newpipe.util.Constants;
|
|
||||||
import org.schabi.newpipe.util.DeviceUtils;
|
import org.schabi.newpipe.util.DeviceUtils;
|
||||||
import org.schabi.newpipe.util.KoreUtil;
|
import org.schabi.newpipe.util.KoreUtil;
|
||||||
import org.schabi.newpipe.util.ListHelper;
|
import org.schabi.newpipe.util.ListHelper;
|
||||||
@ -260,7 +257,12 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||||||
onQueueClosed();
|
onQueueClosed();
|
||||||
// Android TV: without it focus will frame the whole player
|
// Android TV: without it focus will frame the whole player
|
||||||
playPauseButton.requestFocus();
|
playPauseButton.requestFocus();
|
||||||
|
|
||||||
|
if (simpleExoPlayer.getPlayWhenReady()) {
|
||||||
onPlay();
|
onPlay();
|
||||||
|
} else {
|
||||||
|
onPause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
NavigationHelper.sendPlayerStartedEvent(service);
|
NavigationHelper.sendPlayerStartedEvent(service);
|
||||||
}
|
}
|
||||||
@ -756,40 +758,6 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||||||
setupScreenRotationButton();
|
setupScreenRotationButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void switchFromPopupToMain() {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "switchFromPopupToMain() called");
|
|
||||||
}
|
|
||||||
if (!popupPlayerSelected() || simpleExoPlayer == null || getCurrentMetadata() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setRecovery();
|
|
||||||
service.removeViewFromParent();
|
|
||||||
final Intent intent = NavigationHelper.getPlayerIntent(
|
|
||||||
service,
|
|
||||||
MainActivity.class,
|
|
||||||
this.getPlayQueue(),
|
|
||||||
this.getRepeatMode(),
|
|
||||||
this.getPlaybackSpeed(),
|
|
||||||
this.getPlaybackPitch(),
|
|
||||||
this.getPlaybackSkipSilence(),
|
|
||||||
null,
|
|
||||||
true,
|
|
||||||
!isPlaying(),
|
|
||||||
isMuted()
|
|
||||||
);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
intent.putExtra(Constants.KEY_SERVICE_ID,
|
|
||||||
getCurrentMetadata().getMetadata().getServiceId());
|
|
||||||
intent.putExtra(Constants.KEY_LINK_TYPE, StreamingService.LinkType.STREAM);
|
|
||||||
intent.putExtra(Constants.KEY_URL, getVideoUrl());
|
|
||||||
intent.putExtra(Constants.KEY_TITLE, getVideoTitle());
|
|
||||||
intent.putExtra(VideoDetailFragment.AUTO_PLAY, true);
|
|
||||||
service.onDestroy();
|
|
||||||
context.startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final View v) {
|
public void onClick(final View v) {
|
||||||
super.onClick(v);
|
super.onClick(v);
|
||||||
@ -817,7 +785,9 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||||||
} else if (v.getId() == openInBrowser.getId()) {
|
} else if (v.getId() == openInBrowser.getId()) {
|
||||||
onOpenInBrowserClicked();
|
onOpenInBrowserClicked();
|
||||||
} else if (v.getId() == fullscreenButton.getId()) {
|
} else if (v.getId() == fullscreenButton.getId()) {
|
||||||
switchFromPopupToMain();
|
setRecovery();
|
||||||
|
NavigationHelper.playOnMainPlayer(context, getPlayQueue(), true);
|
||||||
|
return;
|
||||||
} else if (v.getId() == screenRotationButton.getId()) {
|
} else if (v.getId() == screenRotationButton.getId()) {
|
||||||
// Only if it's not a vertical video or vertical video but in landscape with locked
|
// Only if it's not a vertical video or vertical video but in landscape with locked
|
||||||
// orientation a screen orientation can be changed automatically
|
// orientation a screen orientation can be changed automatically
|
||||||
|
@ -63,7 +63,7 @@ abstract class BasePlayerGestureListener(
|
|||||||
private var isMovingInPopup = false
|
private var isMovingInPopup = false
|
||||||
private var isResizing = false
|
private var isResizing = false
|
||||||
|
|
||||||
private val tossFlingVelocity = PlayerHelper.getTossFlingVelocity(service)
|
private val tossFlingVelocity = PlayerHelper.getTossFlingVelocity()
|
||||||
|
|
||||||
// [popup] initial coordinates and distance between fingers
|
// [popup] initial coordinates and distance between fingers
|
||||||
private var initPointerDistance = -1.0
|
private var initPointerDistance = -1.0
|
||||||
@ -104,9 +104,6 @@ abstract class BasePlayerGestureListener(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onTouchInPopup(v: View, event: MotionEvent): Boolean {
|
private fun onTouchInPopup(v: View, event: MotionEvent): Boolean {
|
||||||
if (playerImpl == null) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
playerImpl.gestureDetector.onTouchEvent(event)
|
playerImpl.gestureDetector.onTouchEvent(event)
|
||||||
if (event.pointerCount == 2 && !isMovingInPopup && !isResizing) {
|
if (event.pointerCount == 2 && !isMovingInPopup && !isResizing) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -111,10 +111,10 @@ public class PlayerGestureListener
|
|||||||
}
|
}
|
||||||
if (playerType == MainPlayer.PlayerType.VIDEO) {
|
if (playerType == MainPlayer.PlayerType.VIDEO) {
|
||||||
if (portion == DisplayPortion.LEFT_HALF) {
|
if (portion == DisplayPortion.LEFT_HALF) {
|
||||||
onScrollMainVolume(distanceX, distanceY);
|
onScrollMainBrightness(distanceX, distanceY);
|
||||||
|
|
||||||
} else /* DisplayPortion.RIGHT_HALF */ {
|
} else /* DisplayPortion.RIGHT_HALF */ {
|
||||||
onScrollMainBrightness(distanceX, distanceY);
|
onScrollMainVolume(distanceX, distanceY);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else /* MainPlayer.PlayerType.POPUP */ {
|
} else /* MainPlayer.PlayerType.POPUP */ {
|
||||||
|
@ -164,7 +164,7 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, An
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAudioSessionId(final EventTime eventTime, final int audioSessionId) {
|
public void onAudioSessionId(final EventTime eventTime, final int audioSessionId) {
|
||||||
if (!PlayerHelper.isUsingDSP(context)) {
|
if (!PlayerHelper.isUsingDSP()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +295,7 @@ public final class PlayerHelper {
|
|||||||
return 60000;
|
return 60000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TrackSelection.Factory getQualitySelector(@NonNull final Context context) {
|
public static TrackSelection.Factory getQualitySelector() {
|
||||||
return new AdaptiveTrackSelection.Factory(
|
return new AdaptiveTrackSelection.Factory(
|
||||||
1000,
|
1000,
|
||||||
AdaptiveTrackSelection.DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS,
|
AdaptiveTrackSelection.DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS,
|
||||||
@ -303,11 +303,11 @@ public final class PlayerHelper {
|
|||||||
AdaptiveTrackSelection.DEFAULT_BANDWIDTH_FRACTION);
|
AdaptiveTrackSelection.DEFAULT_BANDWIDTH_FRACTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isUsingDSP(@NonNull final Context context) {
|
public static boolean isUsingDSP() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getTossFlingVelocity(@NonNull final Context context) {
|
public static int getTossFlingVelocity() {
|
||||||
return 2500;
|
return 2500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,17 @@ public final class PlayerHolder {
|
|||||||
return player.getPlayerType();
|
return player.getPlayerType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isPlaying() {
|
||||||
|
if (player == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return player.isPlaying();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPlayerOpen() {
|
||||||
|
return player != null;
|
||||||
|
}
|
||||||
|
|
||||||
public static void setListener(final PlayerServiceExtendedEventListener newListener) {
|
public static void setListener(final PlayerServiceExtendedEventListener newListener) {
|
||||||
listener = newListener;
|
listener = newListener;
|
||||||
// Force reload data from service
|
// Force reload data from service
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
package org.schabi.newpipe.player.playqueue;
|
package org.schabi.newpipe.player.playqueue;
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.reactivestreams.Subscriber;
|
|
||||||
import org.reactivestreams.Subscription;
|
|
||||||
import org.schabi.newpipe.MainActivity;
|
import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.player.playqueue.events.AppendEvent;
|
import org.schabi.newpipe.player.playqueue.events.AppendEvent;
|
||||||
import org.schabi.newpipe.player.playqueue.events.ErrorEvent;
|
import org.schabi.newpipe.player.playqueue.events.ErrorEvent;
|
||||||
@ -43,7 +39,6 @@ import io.reactivex.subjects.BehaviorSubject;
|
|||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public abstract class PlayQueue implements Serializable {
|
public abstract class PlayQueue implements Serializable {
|
||||||
private final String TAG = "PlayQueue@" + Integer.toHexString(hashCode());
|
|
||||||
public static final boolean DEBUG = MainActivity.DEBUG;
|
public static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
|
||||||
private ArrayList<PlayQueueItem> backup;
|
private ArrayList<PlayQueueItem> backup;
|
||||||
@ -55,7 +50,6 @@ public abstract class PlayQueue implements Serializable {
|
|||||||
|
|
||||||
private transient BehaviorSubject<PlayQueueEvent> eventBroadcast;
|
private transient BehaviorSubject<PlayQueueEvent> eventBroadcast;
|
||||||
private transient Flowable<PlayQueueEvent> broadcastReceiver;
|
private transient Flowable<PlayQueueEvent> broadcastReceiver;
|
||||||
private transient Subscription reportingReactor;
|
|
||||||
|
|
||||||
private transient boolean disposed;
|
private transient boolean disposed;
|
||||||
|
|
||||||
@ -87,10 +81,6 @@ public abstract class PlayQueue implements Serializable {
|
|||||||
broadcastReceiver = eventBroadcast.toFlowable(BackpressureStrategy.BUFFER)
|
broadcastReceiver = eventBroadcast.toFlowable(BackpressureStrategy.BUFFER)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.startWith(new InitEvent());
|
.startWith(new InitEvent());
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
broadcastReceiver.subscribe(getSelfReporter());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,13 +90,9 @@ public abstract class PlayQueue implements Serializable {
|
|||||||
if (eventBroadcast != null) {
|
if (eventBroadcast != null) {
|
||||||
eventBroadcast.onComplete();
|
eventBroadcast.onComplete();
|
||||||
}
|
}
|
||||||
if (reportingReactor != null) {
|
|
||||||
reportingReactor.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
eventBroadcast = null;
|
eventBroadcast = null;
|
||||||
broadcastReceiver = null;
|
broadcastReceiver = null;
|
||||||
reportingReactor = null;
|
|
||||||
disposed = true;
|
disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,35 +530,5 @@ public abstract class PlayQueue implements Serializable {
|
|||||||
eventBroadcast.onNext(event);
|
eventBroadcast.onNext(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Subscriber<PlayQueueEvent> getSelfReporter() {
|
|
||||||
return new Subscriber<PlayQueueEvent>() {
|
|
||||||
@Override
|
|
||||||
public void onSubscribe(final Subscription s) {
|
|
||||||
if (reportingReactor != null) {
|
|
||||||
reportingReactor.cancel();
|
|
||||||
}
|
|
||||||
reportingReactor = s;
|
|
||||||
reportingReactor.request(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNext(final PlayQueueEvent event) {
|
|
||||||
Log.d(TAG, "Received broadcast: " + event.type().name() + ". "
|
|
||||||
+ "Current index: " + getIndex() + ", play queue length: " + size() + ".");
|
|
||||||
reportingReactor.request(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(final Throwable t) {
|
|
||||||
Log.e(TAG, "Received broadcast error", t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
Log.d(TAG, "Broadcast is shutting down.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +64,20 @@ public class PlayQueueItem implements Serializable {
|
|||||||
this.recoveryPosition = RECOVERY_UNSET;
|
this.recoveryPosition = RECOVERY_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (o instanceof PlayQueueItem) {
|
||||||
|
return url.equals(((PlayQueueItem) o).url);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return url.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return title;
|
return title;
|
||||||
|
@ -18,7 +18,6 @@ import androidx.core.content.ContextCompat;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.fragment.app.FragmentTransaction;
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
import androidx.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
|
|
||||||
@ -38,7 +37,6 @@ import org.schabi.newpipe.extractor.stream.VideoStream;
|
|||||||
import org.schabi.newpipe.fragments.MainFragment;
|
import org.schabi.newpipe.fragments.MainFragment;
|
||||||
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
|
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
|
||||||
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
|
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
|
||||||
import org.schabi.newpipe.fragments.list.comments.CommentsFragment;
|
|
||||||
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
|
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
|
||||||
import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment;
|
import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment;
|
||||||
import org.schabi.newpipe.fragments.list.search.SearchFragment;
|
import org.schabi.newpipe.fragments.list.search.SearchFragment;
|
||||||
@ -52,13 +50,14 @@ import org.schabi.newpipe.player.BackgroundPlayerActivity;
|
|||||||
import org.schabi.newpipe.player.BasePlayer;
|
import org.schabi.newpipe.player.BasePlayer;
|
||||||
import org.schabi.newpipe.player.MainPlayer;
|
import org.schabi.newpipe.player.MainPlayer;
|
||||||
import org.schabi.newpipe.player.VideoPlayer;
|
import org.schabi.newpipe.player.VideoPlayer;
|
||||||
|
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||||
|
import org.schabi.newpipe.player.helper.PlayerHolder;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||||
import org.schabi.newpipe.settings.SettingsActivity;
|
import org.schabi.newpipe.settings.SettingsActivity;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@SuppressWarnings({"unused"})
|
|
||||||
public final class NavigationHelper {
|
public final class NavigationHelper {
|
||||||
public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag";
|
public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag";
|
||||||
public static final String SEARCH_FRAGMENT_TAG = "search_fragment_tag";
|
public static final String SEARCH_FRAGMENT_TAG = "search_fragment_tag";
|
||||||
@ -73,7 +72,6 @@ public final class NavigationHelper {
|
|||||||
public static <T> Intent getPlayerIntent(@NonNull final Context context,
|
public static <T> Intent getPlayerIntent(@NonNull final Context context,
|
||||||
@NonNull final Class<T> targetClazz,
|
@NonNull final Class<T> targetClazz,
|
||||||
@Nullable final PlayQueue playQueue,
|
@Nullable final PlayQueue playQueue,
|
||||||
@Nullable final String quality,
|
|
||||||
final boolean resumePlayback) {
|
final boolean resumePlayback) {
|
||||||
final Intent intent = new Intent(context, targetClazz);
|
final Intent intent = new Intent(context, targetClazz);
|
||||||
|
|
||||||
@ -83,9 +81,6 @@ public final class NavigationHelper {
|
|||||||
intent.putExtra(VideoPlayer.PLAY_QUEUE_KEY, cacheKey);
|
intent.putExtra(VideoPlayer.PLAY_QUEUE_KEY, cacheKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (quality != null) {
|
|
||||||
intent.putExtra(VideoPlayer.PLAYBACK_QUALITY, quality);
|
|
||||||
}
|
|
||||||
intent.putExtra(VideoPlayer.RESUME_PLAYBACK, resumePlayback);
|
intent.putExtra(VideoPlayer.RESUME_PLAYBACK, resumePlayback);
|
||||||
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_VIDEO);
|
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_VIDEO);
|
||||||
|
|
||||||
@ -96,8 +91,10 @@ public final class NavigationHelper {
|
|||||||
public static <T> Intent getPlayerIntent(@NonNull final Context context,
|
public static <T> Intent getPlayerIntent(@NonNull final Context context,
|
||||||
@NonNull final Class<T> targetClazz,
|
@NonNull final Class<T> targetClazz,
|
||||||
@Nullable final PlayQueue playQueue,
|
@Nullable final PlayQueue playQueue,
|
||||||
final boolean resumePlayback) {
|
final boolean resumePlayback,
|
||||||
return getPlayerIntent(context, targetClazz, playQueue, null, resumePlayback);
|
final boolean playWhenReady) {
|
||||||
|
return getPlayerIntent(context, targetClazz, playQueue, resumePlayback)
|
||||||
|
.putExtra(BasePlayer.PLAY_WHEN_READY, playWhenReady);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -111,61 +108,25 @@ public final class NavigationHelper {
|
|||||||
.putExtra(BasePlayer.SELECT_ON_APPEND, selectOnAppend);
|
.putExtra(BasePlayer.SELECT_ON_APPEND, selectOnAppend);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static <T> Intent getPlayerIntent(@NonNull final Context context,
|
|
||||||
@NonNull final Class<T> targetClazz,
|
|
||||||
@Nullable final PlayQueue playQueue,
|
|
||||||
final int repeatMode,
|
|
||||||
final float playbackSpeed,
|
|
||||||
final float playbackPitch,
|
|
||||||
final boolean playbackSkipSilence,
|
|
||||||
@Nullable final String playbackQuality,
|
|
||||||
final boolean resumePlayback,
|
|
||||||
final boolean startPaused,
|
|
||||||
final boolean isMuted) {
|
|
||||||
return getPlayerIntent(context, targetClazz, playQueue, playbackQuality, resumePlayback)
|
|
||||||
.putExtra(BasePlayer.REPEAT_MODE, repeatMode)
|
|
||||||
.putExtra(BasePlayer.START_PAUSED, startPaused)
|
|
||||||
.putExtra(BasePlayer.IS_MUTED, isMuted);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void playOnMainPlayer(final AppCompatActivity activity,
|
public static void playOnMainPlayer(final AppCompatActivity activity,
|
||||||
|
@NonNull final PlayQueue playQueue) {
|
||||||
|
final PlayQueueItem item = playQueue.getItem();
|
||||||
|
assert item != null;
|
||||||
|
openVideoDetailFragment(activity, activity.getSupportFragmentManager(),
|
||||||
|
item.getServiceId(), item.getUrl(), item.getTitle(), playQueue, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void playOnMainPlayer(final Context context,
|
||||||
|
@NonNull final PlayQueue playQueue,
|
||||||
|
final boolean switchingPlayers) {
|
||||||
|
final PlayQueueItem item = playQueue.getItem();
|
||||||
|
assert item != null;
|
||||||
|
openVideoDetail(context,
|
||||||
|
item.getServiceId(), item.getUrl(), item.getTitle(), playQueue, switchingPlayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void playOnPopupPlayer(final Context context,
|
||||||
final PlayQueue queue,
|
final PlayQueue queue,
|
||||||
final boolean autoPlay) {
|
|
||||||
playOnMainPlayer(activity.getSupportFragmentManager(), queue, autoPlay);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void playOnMainPlayer(final FragmentManager fragmentManager,
|
|
||||||
final PlayQueue queue,
|
|
||||||
final boolean autoPlay) {
|
|
||||||
final PlayQueueItem currentStream = queue.getItem();
|
|
||||||
openVideoDetailFragment(
|
|
||||||
fragmentManager,
|
|
||||||
currentStream.getServiceId(),
|
|
||||||
currentStream.getUrl(),
|
|
||||||
currentStream.getTitle(),
|
|
||||||
autoPlay,
|
|
||||||
queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void playOnMainPlayer(@NonNull final Context context,
|
|
||||||
@Nullable final PlayQueue queue,
|
|
||||||
@NonNull final StreamingService.LinkType linkType,
|
|
||||||
@NonNull final String url,
|
|
||||||
@NonNull final String title,
|
|
||||||
final boolean autoPlay,
|
|
||||||
final boolean resumePlayback) {
|
|
||||||
|
|
||||||
final Intent intent = getPlayerIntent(context, MainActivity.class, queue, resumePlayback);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
intent.putExtra(Constants.KEY_LINK_TYPE, linkType);
|
|
||||||
intent.putExtra(Constants.KEY_URL, url);
|
|
||||||
intent.putExtra(Constants.KEY_TITLE, title);
|
|
||||||
intent.putExtra(VideoDetailFragment.AUTO_PLAY, autoPlay);
|
|
||||||
context.startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void playOnPopupPlayer(final Context context, final PlayQueue queue,
|
|
||||||
final boolean resumePlayback) {
|
final boolean resumePlayback) {
|
||||||
if (!PermissionHelper.isPopupEnabled(context)) {
|
if (!PermissionHelper.isPopupEnabled(context)) {
|
||||||
PermissionHelper.showPopupEnablementToast(context);
|
PermissionHelper.showPopupEnablementToast(context);
|
||||||
@ -300,9 +261,6 @@ public final class NavigationHelper {
|
|||||||
.setNegativeButton(R.string.cancel, (dialog, which)
|
.setNegativeButton(R.string.cancel, (dialog, which)
|
||||||
-> Log.i("NavigationHelper", "You unlocked a secret unicorn."))
|
-> Log.i("NavigationHelper", "You unlocked a secret unicorn."))
|
||||||
.show();
|
.show();
|
||||||
// Log.e("NavigationHelper",
|
|
||||||
// "Either no Streaming player for audio was installed, "
|
|
||||||
// + "or something important crashed:");
|
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(context, R.string.no_player_found_toast, Toast.LENGTH_LONG).show();
|
Toast.makeText(context, R.string.no_player_found_toast, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
@ -358,41 +316,6 @@ public final class NavigationHelper {
|
|||||||
.commit();
|
.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openVideoDetailFragment(final FragmentManager fragmentManager,
|
|
||||||
final int serviceId, final String url,
|
|
||||||
final String title) {
|
|
||||||
openVideoDetailFragment(fragmentManager, serviceId, url, title, true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void openVideoDetailFragment(
|
|
||||||
final FragmentManager fragmentManager,
|
|
||||||
final int serviceId,
|
|
||||||
final String url,
|
|
||||||
final String title,
|
|
||||||
final boolean autoPlay,
|
|
||||||
final PlayQueue playQueue) {
|
|
||||||
final Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_player_holder);
|
|
||||||
|
|
||||||
if (fragment instanceof VideoDetailFragment && fragment.isVisible()) {
|
|
||||||
expandMainPlayer(fragment.requireActivity());
|
|
||||||
final VideoDetailFragment detailFragment = (VideoDetailFragment) fragment;
|
|
||||||
detailFragment.setAutoplay(autoPlay);
|
|
||||||
detailFragment
|
|
||||||
.selectAndLoadVideo(serviceId, url, title == null ? "" : title, playQueue);
|
|
||||||
detailFragment.scrollToTop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final VideoDetailFragment instance = VideoDetailFragment
|
|
||||||
.getInstance(serviceId, url, title == null ? "" : title, playQueue);
|
|
||||||
instance.setAutoplay(autoPlay);
|
|
||||||
|
|
||||||
defaultTransaction(fragmentManager)
|
|
||||||
.replace(R.id.fragment_player_holder, instance)
|
|
||||||
.runOnCommit(() -> expandMainPlayer(instance.requireActivity()))
|
|
||||||
.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void expandMainPlayer(final Context context) {
|
public static void expandMainPlayer(final Context context) {
|
||||||
context.sendBroadcast(new Intent(VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER));
|
context.sendBroadcast(new Intent(VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER));
|
||||||
}
|
}
|
||||||
@ -409,33 +332,76 @@ public final class NavigationHelper {
|
|||||||
.commitAllowingStateLoss();
|
.commitAllowingStateLoss();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openChannelFragment(final FragmentManager fragmentManager,
|
private interface RunnableWithVideoDetailFragment {
|
||||||
final int serviceId, final String url,
|
void run(VideoDetailFragment detailFragment);
|
||||||
final String name) {
|
|
||||||
defaultTransaction(fragmentManager)
|
|
||||||
.replace(R.id.fragment_holder, ChannelFragment.getInstance(serviceId, url,
|
|
||||||
name == null ? "" : name))
|
|
||||||
.addToBackStack(null)
|
|
||||||
.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openCommentsFragment(final FragmentManager fragmentManager,
|
public static void openVideoDetailFragment(@NonNull final Context context,
|
||||||
|
@NonNull final FragmentManager fragmentManager,
|
||||||
|
final int serviceId,
|
||||||
|
@Nullable final String url,
|
||||||
|
@NonNull final String title,
|
||||||
|
@Nullable final PlayQueue playQueue,
|
||||||
|
final boolean switchingPlayers) {
|
||||||
|
|
||||||
|
final boolean autoPlay;
|
||||||
|
@Nullable final MainPlayer.PlayerType playerType = PlayerHolder.getType();
|
||||||
|
if (playerType == null) {
|
||||||
|
// no player open
|
||||||
|
autoPlay = PlayerHelper.isAutoplayAllowedByUser(context);
|
||||||
|
} else if (switchingPlayers) {
|
||||||
|
// switching player to main player
|
||||||
|
autoPlay = PlayerHolder.isPlaying(); // keep play/pause state
|
||||||
|
} else if (playerType == MainPlayer.PlayerType.VIDEO) {
|
||||||
|
// opening new stream while already playing in main player
|
||||||
|
autoPlay = PlayerHelper.isAutoplayAllowedByUser(context);
|
||||||
|
} else {
|
||||||
|
// opening new stream while already playing in another player
|
||||||
|
autoPlay = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final RunnableWithVideoDetailFragment onVideoDetailFragmentReady = (detailFragment) -> {
|
||||||
|
expandMainPlayer(detailFragment.requireActivity());
|
||||||
|
detailFragment.setAutoPlay(autoPlay);
|
||||||
|
if (switchingPlayers) {
|
||||||
|
// Situation when user switches from players to main player. All needed data is
|
||||||
|
// here, we can start watching (assuming newQueue equals playQueue).
|
||||||
|
detailFragment.openVideoPlayer();
|
||||||
|
} else {
|
||||||
|
detailFragment.selectAndLoadVideo(serviceId, url, title, playQueue);
|
||||||
|
}
|
||||||
|
detailFragment.scrollToTop();
|
||||||
|
};
|
||||||
|
|
||||||
|
final Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_player_holder);
|
||||||
|
if (fragment instanceof VideoDetailFragment && fragment.isVisible()) {
|
||||||
|
onVideoDetailFragmentReady.run((VideoDetailFragment) fragment);
|
||||||
|
} else {
|
||||||
|
final VideoDetailFragment instance = VideoDetailFragment
|
||||||
|
.getInstance(serviceId, url, title, playQueue);
|
||||||
|
instance.setAutoPlay(autoPlay);
|
||||||
|
|
||||||
|
defaultTransaction(fragmentManager)
|
||||||
|
.replace(R.id.fragment_player_holder, instance)
|
||||||
|
.runOnCommit(() -> onVideoDetailFragmentReady.run(instance))
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void openChannelFragment(final FragmentManager fragmentManager,
|
||||||
final int serviceId, final String url,
|
final int serviceId, final String url,
|
||||||
final String name) {
|
@NonNull final String name) {
|
||||||
fragmentManager.beginTransaction()
|
defaultTransaction(fragmentManager)
|
||||||
.setCustomAnimations(R.anim.switch_service_in, R.anim.switch_service_out)
|
.replace(R.id.fragment_holder, ChannelFragment.getInstance(serviceId, url, name))
|
||||||
.replace(R.id.fragment_holder, CommentsFragment.getInstance(serviceId, url,
|
|
||||||
name == null ? "" : name))
|
|
||||||
.addToBackStack(null)
|
.addToBackStack(null)
|
||||||
.commit();
|
.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openPlaylistFragment(final FragmentManager fragmentManager,
|
public static void openPlaylistFragment(final FragmentManager fragmentManager,
|
||||||
final int serviceId, final String url,
|
final int serviceId, final String url,
|
||||||
final String name) {
|
@NonNull final String name) {
|
||||||
defaultTransaction(fragmentManager)
|
defaultTransaction(fragmentManager)
|
||||||
.replace(R.id.fragment_holder, PlaylistFragment.getInstance(serviceId, url,
|
.replace(R.id.fragment_holder, PlaylistFragment.getInstance(serviceId, url, name))
|
||||||
name == null ? "" : name))
|
|
||||||
.addToBackStack(null)
|
.addToBackStack(null)
|
||||||
.commit();
|
.commit();
|
||||||
}
|
}
|
||||||
@ -511,33 +477,26 @@ public final class NavigationHelper {
|
|||||||
context.startActivity(mIntent);
|
context.startActivity(mIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openChannel(final Context context, final int serviceId, final String url) {
|
public static void openVideoDetail(final Context context,
|
||||||
openChannel(context, serviceId, url, null);
|
final int serviceId,
|
||||||
}
|
final String url,
|
||||||
|
@NonNull final String title,
|
||||||
|
@Nullable final PlayQueue playQueue,
|
||||||
|
final boolean switchingPlayers) {
|
||||||
|
|
||||||
public static void openChannel(final Context context, final int serviceId,
|
final Intent intent = getOpenIntent(context, url, serviceId,
|
||||||
final String url, final String name) {
|
|
||||||
final Intent openIntent = getOpenIntent(context, url, serviceId,
|
|
||||||
StreamingService.LinkType.CHANNEL);
|
|
||||||
if (name != null && !name.isEmpty()) {
|
|
||||||
openIntent.putExtra(Constants.KEY_TITLE, name);
|
|
||||||
}
|
|
||||||
context.startActivity(openIntent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void openVideoDetail(final Context context, final int serviceId,
|
|
||||||
final String url) {
|
|
||||||
openVideoDetail(context, serviceId, url, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void openVideoDetail(final Context context, final int serviceId,
|
|
||||||
final String url, final String title) {
|
|
||||||
final Intent openIntent = getOpenIntent(context, url, serviceId,
|
|
||||||
StreamingService.LinkType.STREAM);
|
StreamingService.LinkType.STREAM);
|
||||||
if (title != null && !title.isEmpty()) {
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
openIntent.putExtra(Constants.KEY_TITLE, title);
|
intent.putExtra(Constants.KEY_TITLE, title);
|
||||||
|
intent.putExtra(VideoDetailFragment.KEY_SWITCHING_PLAYERS, switchingPlayers);
|
||||||
|
|
||||||
|
if (playQueue != null) {
|
||||||
|
final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class);
|
||||||
|
if (cacheKey != null) {
|
||||||
|
intent.putExtra(VideoPlayer.PLAY_QUEUE_KEY, cacheKey);
|
||||||
}
|
}
|
||||||
context.startActivity(openIntent);
|
}
|
||||||
|
context.startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openMainActivity(final Context context) {
|
public static void openMainActivity(final Context context) {
|
||||||
@ -550,7 +509,6 @@ public final class NavigationHelper {
|
|||||||
public static void openRouterActivity(final Context context, final String url) {
|
public static void openRouterActivity(final Context context, final String url) {
|
||||||
final Intent mIntent = new Intent(context, RouterActivity.class);
|
final Intent mIntent = new Intent(context, RouterActivity.class);
|
||||||
mIntent.setData(Uri.parse(url));
|
mIntent.setData(Uri.parse(url));
|
||||||
mIntent.putExtra(RouterActivity.INTERNAL_ROUTE_KEY, true);
|
|
||||||
context.startActivity(mIntent);
|
context.startActivity(mIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,14 +522,12 @@ public final class NavigationHelper {
|
|||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean openDownloads(final Activity activity) {
|
public static void openDownloads(final Activity activity) {
|
||||||
if (!PermissionHelper.checkStoragePermissions(
|
if (PermissionHelper.checkStoragePermissions(
|
||||||
activity, PermissionHelper.DOWNLOADS_REQUEST_CODE)) {
|
activity, PermissionHelper.DOWNLOADS_REQUEST_CODE)) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final Intent intent = new Intent(activity, DownloadActivity.class);
|
final Intent intent = new Intent(activity, DownloadActivity.class);
|
||||||
activity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
return true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Intent getPlayQueueActivityIntent(final Context context) {
|
public static Intent getPlayQueueActivityIntent(final Context context) {
|
||||||
@ -600,7 +556,8 @@ public final class NavigationHelper {
|
|||||||
return getIntentByLink(context, NewPipe.getServiceByUrl(url), url);
|
return getIntentByLink(context, NewPipe.getServiceByUrl(url), url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Intent getIntentByLink(final Context context, final StreamingService service,
|
public static Intent getIntentByLink(final Context context,
|
||||||
|
final StreamingService service,
|
||||||
final String url) throws ExtractionException {
|
final String url) throws ExtractionException {
|
||||||
final StreamingService.LinkType linkType = service.getLinkTypeByUrl(url);
|
final StreamingService.LinkType linkType = service.getLinkTypeByUrl(url);
|
||||||
|
|
||||||
@ -609,15 +566,7 @@ public final class NavigationHelper {
|
|||||||
+ " url=" + url);
|
+ " url=" + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Intent rIntent = getOpenIntent(context, url, service.getServiceId(), linkType);
|
return getOpenIntent(context, url, service.getServiceId(), linkType);
|
||||||
|
|
||||||
if (linkType == StreamingService.LinkType.STREAM) {
|
|
||||||
rIntent.putExtra(VideoDetailFragment.AUTO_PLAY,
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
|
|
||||||
context.getString(R.string.autoplay_through_intent_key), false));
|
|
||||||
}
|
|
||||||
|
|
||||||
return rIntent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Uri openMarketUrl(final String packageName) {
|
private static Uri openMarketUrl(final String packageName) {
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
<string name="use_external_video_player_key" translatable="false">use_external_video_player</string>
|
<string name="use_external_video_player_key" translatable="false">use_external_video_player</string>
|
||||||
<string name="use_external_audio_player_key" translatable="false">use_external_audio_player</string>
|
<string name="use_external_audio_player_key" translatable="false">use_external_audio_player</string>
|
||||||
<string name="autoplay_through_intent_key" translatable="false">autoplay_through_intent</string>
|
|
||||||
<string name="use_old_player_key" translatable="false">use_oldplayer</string>
|
<string name="use_old_player_key" translatable="false">use_oldplayer</string>
|
||||||
|
|
||||||
<string name="volume_gesture_control_key" translatable="false">volume_gesture_control</string>
|
<string name="volume_gesture_control_key" translatable="false">volume_gesture_control</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user