Merged 'dev' branch
This commit is contained in:
commit
0370fa6c00
143 changed files with 4952 additions and 1792 deletions
|
|
@ -122,6 +122,7 @@ import io.reactivex.schedulers.Schedulers;
|
|||
|
||||
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
|
||||
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
|
||||
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
|
||||
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
|
||||
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||
|
|
@ -327,7 +328,7 @@ public class VideoDetailFragment
|
|||
settingsContentObserver = new ContentObserver(new Handler()) {
|
||||
@Override
|
||||
public void onChange(final boolean selfChange) {
|
||||
if (activity != null && !PlayerHelper.globalScreenOrientationLocked(activity)) {
|
||||
if (activity != null && !globalScreenOrientationLocked(activity)) {
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
|
@ -853,6 +854,9 @@ public class VideoDetailFragment
|
|||
return;
|
||||
}
|
||||
setInitialData(sid, videoUrl, title, queue);
|
||||
if (player != null) {
|
||||
player.disablePreloadingOfCurrentTrack();
|
||||
}
|
||||
startLoading(false, true);
|
||||
}
|
||||
|
||||
|
|
@ -1143,7 +1147,7 @@ public class VideoDetailFragment
|
|||
}
|
||||
|
||||
private boolean isExternalPlayerEnabled() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(getContext())
|
||||
return PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
.getBoolean(getString(R.string.use_external_video_player_key), false);
|
||||
}
|
||||
|
||||
|
|
@ -1154,23 +1158,7 @@ public class VideoDetailFragment
|
|||
&& !isExternalPlayerEnabled()
|
||||
&& (player == null || player.videoPlayerSelected())
|
||||
&& bottomSheetState != BottomSheetBehavior.STATE_HIDDEN
|
||||
&& isAutoplayAllowedByUser();
|
||||
}
|
||||
|
||||
private boolean isAutoplayAllowedByUser() {
|
||||
if (activity == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (PlayerHelper.getAutoplayType(activity)) {
|
||||
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER:
|
||||
return false;
|
||||
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI:
|
||||
return !ListHelper.isMeteredNetwork(activity);
|
||||
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
&& PlayerHelper.isAutoplayAllowedByUser(requireContext());
|
||||
}
|
||||
|
||||
private void addVideoPlayerView() {
|
||||
|
|
@ -1759,9 +1747,6 @@ public class VideoDetailFragment
|
|||
setOverlayPlayPauseImage();
|
||||
|
||||
switch (state) {
|
||||
case BasePlayer.STATE_COMPLETED:
|
||||
restoreDefaultOrientation();
|
||||
break;
|
||||
case BasePlayer.STATE_PLAYING:
|
||||
if (positionView.getAlpha() != 1.0f
|
||||
&& player.getPlayQueue() != null
|
||||
|
|
@ -1865,7 +1850,13 @@ public class VideoDetailFragment
|
|||
}
|
||||
scrollToTop();
|
||||
|
||||
addVideoPlayerView();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
addVideoPlayerView();
|
||||
} else {
|
||||
// KitKat needs a delay before addVideoPlayerView call or it reports wrong height in
|
||||
// activity.getWindow().getDecorView().getHeight()
|
||||
new Handler().post(this::addVideoPlayerView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1873,13 +1864,15 @@ public class VideoDetailFragment
|
|||
// In tablet user experience will be better if screen will not be rotated
|
||||
// from landscape to portrait every time.
|
||||
// Just turn on fullscreen mode in landscape orientation
|
||||
if (isLandscape() && DeviceUtils.isTablet(activity)) {
|
||||
// or portrait & unlocked global orientation
|
||||
if (DeviceUtils.isTablet(activity)
|
||||
&& (!globalScreenOrientationLocked(activity) || isLandscape())) {
|
||||
player.toggleFullscreen();
|
||||
return;
|
||||
}
|
||||
|
||||
final int newOrientation = isLandscape()
|
||||
? ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
||||
? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
: ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
|
||||
|
||||
activity.setRequestedOrientation(newOrientation);
|
||||
|
|
@ -2022,9 +2015,8 @@ public class VideoDetailFragment
|
|||
}
|
||||
|
||||
player.checkLandscape();
|
||||
final boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(activity);
|
||||
// Let's give a user time to look at video information page if video is not playing
|
||||
if (orientationLocked && !player.isPlaying()) {
|
||||
if (globalScreenOrientationLocked(activity) && !player.isPlaying()) {
|
||||
player.onPlay();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ import org.schabi.newpipe.report.UserAction;
|
|||
import org.schabi.newpipe.util.DeviceUtils;
|
||||
import org.schabi.newpipe.util.AnimationUtils;
|
||||
import org.schabi.newpipe.util.Constants;
|
||||
import org.schabi.newpipe.util.ExceptionUtils;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.ServiceHelper;
|
||||
|
|
@ -78,7 +79,7 @@ import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovement
|
|||
import static java.util.Arrays.asList;
|
||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||
|
||||
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage>
|
||||
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage<?>>
|
||||
implements BackPressable {
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Search
|
||||
|
|
@ -133,7 +134,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
private Map<Integer, String> menuItemToFilterName;
|
||||
private StreamingService service;
|
||||
private Page nextPage;
|
||||
private String contentCountry;
|
||||
private boolean isSuggestionsEnabled = true;
|
||||
|
||||
private Disposable searchDisposable;
|
||||
|
|
@ -154,6 +154,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
private TextView correctSuggestion;
|
||||
|
||||
private View suggestionsPanel;
|
||||
private boolean suggestionsPanelVisible = false;
|
||||
private RecyclerView suggestionsRecyclerView;
|
||||
|
||||
/*////////////////////////////////////////////////////////////////////////*/
|
||||
|
|
@ -204,8 +205,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
= PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
isSuggestionsEnabled = preferences
|
||||
.getBoolean(getString(R.string.show_search_suggestions_key), true);
|
||||
contentCountry = preferences.getString(getString(R.string.content_country_key),
|
||||
getString(R.string.default_localization_key));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -233,9 +232,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
if (suggestionDisposable != null) {
|
||||
suggestionDisposable.dispose();
|
||||
}
|
||||
if (disposables != null) {
|
||||
disposables.clear();
|
||||
}
|
||||
disposables.clear();
|
||||
hideKeyboardSearch();
|
||||
}
|
||||
|
||||
|
|
@ -249,8 +246,8 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
try {
|
||||
service = NewPipe.getService(serviceId);
|
||||
} catch (final Exception e) {
|
||||
ErrorActivity.reportError(getActivity(), e, getActivity().getClass(),
|
||||
getActivity().findViewById(android.R.id.content),
|
||||
ErrorActivity.reportError(getActivity(), e, requireActivity().getClass(),
|
||||
requireActivity().findViewById(android.R.id.content),
|
||||
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
||||
"",
|
||||
"", R.string.general_error));
|
||||
|
|
@ -303,26 +300,20 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
if (suggestionDisposable != null) {
|
||||
suggestionDisposable.dispose();
|
||||
}
|
||||
if (disposables != null) {
|
||||
disposables.clear();
|
||||
}
|
||||
disposables.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
||||
switch (requestCode) {
|
||||
case ReCaptchaActivity.RECAPTCHA_REQUEST:
|
||||
if (resultCode == Activity.RESULT_OK
|
||||
&& !TextUtils.isEmpty(searchString)) {
|
||||
search(searchString, contentFilter, sortFilter);
|
||||
} else {
|
||||
Log.e(TAG, "ReCaptcha failed");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.e(TAG, "Request code from activity not supported [" + requestCode + "]");
|
||||
break;
|
||||
if (requestCode == ReCaptchaActivity.RECAPTCHA_REQUEST) {
|
||||
if (resultCode == Activity.RESULT_OK
|
||||
&& !TextUtils.isEmpty(searchString)) {
|
||||
search(searchString, contentFilter, sortFilter);
|
||||
} else {
|
||||
Log.e(TAG, "ReCaptcha failed");
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Request code from activity not supported [" + requestCode + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -340,7 +331,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
@Override
|
||||
public int getMovementFlags(@NonNull final RecyclerView recyclerView,
|
||||
@NonNull final RecyclerView.ViewHolder viewHolder) {
|
||||
return getSuggestionMovementFlags(recyclerView, viewHolder);
|
||||
return getSuggestionMovementFlags(viewHolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -352,7 +343,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
|
||||
@Override
|
||||
public void onSwiped(@NonNull final RecyclerView.ViewHolder viewHolder, final int i) {
|
||||
onSuggestionItemSwiped(viewHolder, i);
|
||||
onSuggestionItemSwiped(viewHolder);
|
||||
}
|
||||
}).attachToRecyclerView(suggestionsRecyclerView);
|
||||
|
||||
|
|
@ -627,6 +618,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
if (DEBUG) {
|
||||
Log.d(TAG, "showSuggestionsPanel() called");
|
||||
}
|
||||
suggestionsPanelVisible = true;
|
||||
animateView(suggestionsPanel, AnimationUtils.Type.LIGHT_SLIDE_AND_ALPHA, true, 200);
|
||||
}
|
||||
|
||||
|
|
@ -634,6 +626,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
if (DEBUG) {
|
||||
Log.d(TAG, "hideSuggestionsPanel() called");
|
||||
}
|
||||
suggestionsPanelVisible = false;
|
||||
animateView(suggestionsPanel, AnimationUtils.Type.LIGHT_SLIDE_AND_ALPHA, false, 200);
|
||||
}
|
||||
|
||||
|
|
@ -669,8 +662,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
}
|
||||
|
||||
private void showDeleteSuggestionDialog(final SuggestionItem item) {
|
||||
if (activity == null || historyRecordManager == null || suggestionPublisher == null
|
||||
|| searchEditText == null || disposables == null) {
|
||||
if (activity == null || historyRecordManager == null || searchEditText == null) {
|
||||
return;
|
||||
}
|
||||
final String query = item.query;
|
||||
|
|
@ -695,7 +687,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
|
||||
@Override
|
||||
public boolean onBackPressed() {
|
||||
if (suggestionsPanel.getVisibility() == View.VISIBLE
|
||||
if (suggestionsPanelVisible
|
||||
&& infoListAdapter.getItemsList().size() > 0
|
||||
&& !isLoading.get()) {
|
||||
hideSuggestionsPanel();
|
||||
|
|
@ -742,6 +734,13 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
|
||||
final Observable<List<SuggestionItem>> network = ExtractorHelper
|
||||
.suggestionsFor(serviceId, query)
|
||||
.onErrorReturn(throwable -> {
|
||||
if (!ExceptionUtils.isNetworkRelated(throwable)) {
|
||||
showSnackBarError(throwable, UserAction.GET_SUGGESTIONS,
|
||||
NewPipe.getNameOfService(serviceId), searchString, 0);
|
||||
}
|
||||
return new ArrayList<>();
|
||||
})
|
||||
.toObservable()
|
||||
.map(strings -> {
|
||||
final List<SuggestionItem> result = new ArrayList<>();
|
||||
|
|
@ -791,28 +790,30 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
// no-op
|
||||
}
|
||||
|
||||
private void search(final String ss, final String[] cf, final String sf) {
|
||||
private void search(final String theSearchString,
|
||||
final String[] theContentFilter,
|
||||
final String theSortFilter) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "search() called with: query = [" + ss + "]");
|
||||
Log.d(TAG, "search() called with: query = [" + theSearchString + "]");
|
||||
}
|
||||
if (ss.isEmpty()) {
|
||||
if (theSearchString.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final StreamingService streamingService = NewPipe.getServiceByUrl(ss);
|
||||
final StreamingService streamingService = NewPipe.getServiceByUrl(theSearchString);
|
||||
if (streamingService != null) {
|
||||
showLoading();
|
||||
disposables.add(Observable
|
||||
.fromCallable(() ->
|
||||
NavigationHelper.getIntentByLink(activity, streamingService, ss))
|
||||
.fromCallable(() -> NavigationHelper.getIntentByLink(activity,
|
||||
streamingService, theSearchString))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(intent -> {
|
||||
getFM().popBackStackImmediate();
|
||||
activity.startActivity(intent);
|
||||
}, throwable ->
|
||||
showError(getString(R.string.url_not_supported_toast), false)));
|
||||
showError(getString(R.string.unsupported_url), false)));
|
||||
return;
|
||||
}
|
||||
} catch (final Exception ignored) {
|
||||
|
|
@ -820,29 +821,27 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
}
|
||||
|
||||
lastSearchedString = this.searchString;
|
||||
this.searchString = ss;
|
||||
this.searchString = theSearchString;
|
||||
infoListAdapter.clearStreamItemList();
|
||||
hideSuggestionsPanel();
|
||||
hideKeyboardSearch();
|
||||
|
||||
historyRecordManager.onSearched(serviceId, ss)
|
||||
disposables.add(historyRecordManager.onSearched(serviceId, theSearchString)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
ignored -> {
|
||||
},
|
||||
error -> showSnackBarError(error, UserAction.SEARCHED,
|
||||
NewPipe.getNameOfService(serviceId), ss, 0)
|
||||
);
|
||||
suggestionPublisher.onNext(ss);
|
||||
NewPipe.getNameOfService(serviceId), theSearchString, 0)
|
||||
));
|
||||
suggestionPublisher.onNext(theSearchString);
|
||||
startLoading(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startLoading(final boolean forceLoad) {
|
||||
super.startLoading(forceLoad);
|
||||
if (disposables != null) {
|
||||
disposables.clear();
|
||||
}
|
||||
disposables.clear();
|
||||
if (searchDisposable != null) {
|
||||
searchDisposable.dispose();
|
||||
}
|
||||
|
|
@ -881,8 +880,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
|
||||
@Override
|
||||
protected boolean hasMoreItems() {
|
||||
// TODO: No way to tell if search has more items in the moment
|
||||
return true;
|
||||
return Page.isValid(nextPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -895,22 +893,25 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
// Utils
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private void changeContentFilter(final MenuItem item, final List<String> cf) {
|
||||
this.filterItemCheckedId = item.getItemId();
|
||||
private void changeContentFilter(final MenuItem item, final List<String> theContentFilter) {
|
||||
filterItemCheckedId = item.getItemId();
|
||||
item.setChecked(true);
|
||||
|
||||
this.contentFilter = new String[]{cf.get(0)};
|
||||
contentFilter = new String[]{theContentFilter.get(0)};
|
||||
|
||||
if (!TextUtils.isEmpty(searchString)) {
|
||||
search(searchString, this.contentFilter, sortFilter);
|
||||
search(searchString, contentFilter, sortFilter);
|
||||
}
|
||||
}
|
||||
|
||||
private void setQuery(final int sid, final String ss, final String[] cf, final String sf) {
|
||||
this.serviceId = sid;
|
||||
this.searchString = searchString;
|
||||
this.contentFilter = cf;
|
||||
this.sortFilter = sf;
|
||||
private void setQuery(final int theServiceId,
|
||||
final String theSearchString,
|
||||
final String[] theContentFilter,
|
||||
final String theSortFilter) {
|
||||
serviceId = theServiceId;
|
||||
searchString = theSearchString;
|
||||
contentFilter = theContentFilter;
|
||||
sortFilter = theSortFilter;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -924,7 +925,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
suggestionsRecyclerView.smoothScrollToPosition(0);
|
||||
suggestionsRecyclerView.post(() -> suggestionListAdapter.setItems(suggestions));
|
||||
|
||||
if (errorPanelRoot.getVisibility() == View.VISIBLE) {
|
||||
if (suggestionsPanelVisible && errorPanelRoot.getVisibility() == View.VISIBLE) {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
|
@ -1027,7 +1028,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
}
|
||||
|
||||
@Override
|
||||
public void handleNextItems(final ListExtractor.InfoItemsPage result) {
|
||||
public void handleNextItems(final ListExtractor.InfoItemsPage<?> result) {
|
||||
showListFooter(false);
|
||||
infoListAdapter.addInfoItemList(result.getItems());
|
||||
nextPage = result.getNextPage();
|
||||
|
|
@ -1066,8 +1067,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
// Suggestion item touch helper
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
public int getSuggestionMovementFlags(@NonNull final RecyclerView recyclerView,
|
||||
@NonNull final RecyclerView.ViewHolder viewHolder) {
|
||||
public int getSuggestionMovementFlags(@NonNull final RecyclerView.ViewHolder viewHolder) {
|
||||
final int position = viewHolder.getAdapterPosition();
|
||||
if (position == RecyclerView.NO_POSITION) {
|
||||
return 0;
|
||||
|
|
@ -1078,8 +1078,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) : 0;
|
||||
}
|
||||
|
||||
public void onSuggestionItemSwiped(@NonNull final RecyclerView.ViewHolder viewHolder,
|
||||
final int i) {
|
||||
public void onSuggestionItemSwiped(@NonNull final RecyclerView.ViewHolder viewHolder) {
|
||||
final int position = viewHolder.getAdapterPosition();
|
||||
final String query = suggestionListAdapter.getItem(position).query;
|
||||
final Disposable onDelete = historyRecordManager.deleteSearchHistory(query)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue