Move things back to its original place

This commit is contained in:
wb9688 2020-04-02 13:51:10 +02:00
parent fda5405e48
commit 63bcc04eff
35 changed files with 630 additions and 499 deletions

View File

@ -204,7 +204,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
*
* @param versionName Name of new version
* @param apkLocationUrl Url with the new apk
* @param versionCode V
* @param versionCode Code of new version
*/
private void compareAppVersionAndShowNotification(final String versionName,
final String apkLocationUrl,

View File

@ -86,35 +86,41 @@ public class DownloadDialog extends DialogFragment
private static final String TAG = "DialogFragment";
private static final boolean DEBUG = MainActivity.DEBUG;
private static final int REQUEST_DOWNLOAD_SAVE_AS = 0x1230;
private final CompositeDisposable disposables = new CompositeDisposable();
@State
protected StreamInfo currentInfo;
StreamInfo currentInfo;
@State
protected StreamSizeWrapper<AudioStream> wrappedAudioStreams = StreamSizeWrapper.empty();
StreamSizeWrapper<AudioStream> wrappedAudioStreams = StreamSizeWrapper.empty();
@State
protected StreamSizeWrapper<VideoStream> wrappedVideoStreams = StreamSizeWrapper.empty();
StreamSizeWrapper<VideoStream> wrappedVideoStreams = StreamSizeWrapper.empty();
@State
protected StreamSizeWrapper<SubtitlesStream> wrappedSubtitleStreams = StreamSizeWrapper.empty();
StreamSizeWrapper<SubtitlesStream> wrappedSubtitleStreams = StreamSizeWrapper.empty();
@State
protected int selectedVideoIndex = 0;
int selectedVideoIndex = 0;
@State
protected int selectedAudioIndex = 0;
int selectedAudioIndex = 0;
@State
protected int selectedSubtitleIndex = 0;
int selectedSubtitleIndex = 0;
private StoredDirectoryHelper mainStorageAudio = null;
private StoredDirectoryHelper mainStorageVideo = null;
private DownloadManager downloadManager = null;
private ActionMenuItemView okButton = null;
private Context context;
private boolean askForSavePath;
private StreamItemAdapter<AudioStream, Stream> audioStreamsAdapter;
private StreamItemAdapter<VideoStream, AudioStream> videoStreamsAdapter;
private StreamItemAdapter<SubtitlesStream, Stream> subtitleStreamsAdapter;
private final CompositeDisposable disposables = new CompositeDisposable();
private EditText nameEditText;
private Spinner streamsSpinner;
private RadioGroup radioStreamsGroup;
private TextView threadsCountTextView;
private SeekBar threadsSeekBar;
private SharedPreferences prefs;
public static DownloadDialog newInstance(final StreamInfo info) {

View File

@ -109,54 +109,55 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
implements BackPressable, SharedPreferences.OnSharedPreferenceChangeListener,
View.OnClickListener, View.OnLongClickListener {
public static final String AUTO_PLAY = "auto_play";
private int updateFlags = 0;
private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1;
private static final int RESOLUTIONS_MENU_UPDATE_FLAG = 0x2;
private static final int TOOLBAR_ITEMS_UPDATE_FLAG = 0x4;
private static final int COMMENTS_UPDATE_FLAG = 0x8;
private static final String COMMENTS_TAB_TAG = "COMMENTS";
private static final String RELATED_TAB_TAG = "NEXT VIDEO";
private static final String EMPTY_TAB_TAG = "EMPTY TAB";
private static final String INFO_KEY = "info_key";
private static final String STACK_KEY = "stack_key";
/**
* Stack that contains the "navigation history".<br>
* The peek is the current video.
*/
private final LinkedList<StackItem> stack = new LinkedList<>();
private boolean autoPlayEnabled;
private boolean showRelatedStreams;
private boolean showComments;
private String selectedTabTag;
@State
protected int serviceId = Constants.NO_SERVICE_ID;
@State
protected String name;
@State
protected String url;
private int updateFlags = 0;
private boolean autoPlayEnabled;
private boolean showRelatedStreams;
private boolean showComments;
private String selectedTabTag;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private StreamInfo currentInfo;
private Disposable currentWorker;
@NonNull
private CompositeDisposable disposables = new CompositeDisposable();
@Nullable
private Disposable positionSubscriber = null;
private List<VideoStream> sortedVideoStreams;
private int selectedVideoStreamIndex = -1;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private Menu menu;
private Spinner spinnerToolbar;
private LinearLayout contentRootLayoutHiding;
private View thumbnailBackgroundButton;
private ImageView thumbnailImageView;
private ImageView thumbnailPlayButton;
private AnimatedProgressBar positionView;
private View videoTitleRoot;
private TextView videoTitleTextView;
private ImageView videoTitleToggleArrow;
private TextView videoCountView;
private TextView detailControlsBackground;
private TextView detailControlsPopup;
private TextView detailControlsAddToPlaylist;
@ -164,30 +165,42 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
private TextView appendControlsDetail;
private TextView detailDurationView;
private TextView detailPositionView;
private LinearLayout videoDescriptionRootLayout;
private TextView videoUploadDateView;
private TextView videoDescriptionView;
private View uploaderRootLayout;
private TextView uploaderTextView;
private ImageView uploaderThumb;
private TextView thumbsUpTextView;
private ImageView thumbsUpImageView;
private TextView thumbsDownTextView;
private ImageView thumbsDownImageView;
private TextView thumbsDisabledTextView;
private AppBarLayout appBarLayout;
private ViewPager viewPager;
/*////////////////////////////////////////////////////////////////////////*/
private TabAdaptor pageAdapter;
/*//////////////////////////////////////////////////////////////////////////
// Fragment's Lifecycle
//////////////////////////////////////////////////////////////////////////*/
private TabLayout tabLayout;
private FrameLayout relatedStreamsLayout;
/*////////////////////////////////////////////////////////////////////////*/
private static final String COMMENTS_TAB_TAG = "COMMENTS";
private static final String RELATED_TAB_TAG = "NEXT VIDEO";
private static final String EMPTY_TAB_TAG = "EMPTY TAB";
private static final String INFO_KEY = "info_key";
private static final String STACK_KEY = "stack_key";
/**
* Stack that contains the "navigation history".<br>
* The peek is the current video.
*/
private final LinkedList<StackItem> stack = new LinkedList<>();
public static VideoDetailFragment getInstance(final int serviceId, final String videoUrl,
final String name) {
VideoDetailFragment instance = new VideoDetailFragment();
@ -195,6 +208,11 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
return instance;
}
/*//////////////////////////////////////////////////////////////////////////
// Fragment's Lifecycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -285,10 +303,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
disposables = null;
}
/*//////////////////////////////////////////////////////////////////////////
// State Saving
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onDestroyView() {
if (DEBUG) {
@ -336,6 +350,10 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
}
}
/*//////////////////////////////////////////////////////////////////////////
// State Saving
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
@ -351,10 +369,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
outState.putSerializable(STACK_KEY, stack);
}
/*//////////////////////////////////////////////////////////////////////////
// OnClick
//////////////////////////////////////////////////////////////////////////*/
@Override
protected void onRestoreInstanceState(@NonNull final Bundle savedState) {
super.onRestoreInstanceState(savedState);
@ -371,9 +385,12 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
//noinspection unchecked
stack.addAll((Collection<? extends StackItem>) serializable);
}
}
/*//////////////////////////////////////////////////////////////////////////
// OnClick
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onClick(final View v) {
if (isLoading.get() || currentInfo == null) {
@ -449,10 +466,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
private void toggleTitleAndDescription() {
if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
videoTitleTextView.setMaxLines(1);
@ -465,6 +478,10 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
}
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
@Override
protected void initViews(final View rootView, final Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
@ -553,11 +570,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
};
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
private void initThumbnailViews(@NonNull final StreamInfo info) {
thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
if (!TextUtils.isEmpty(info.getThumbnailUrl())) {
@ -581,6 +593,10 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
}
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(final Menu m, final MenuInflater inflater) {
this.menu = m;
@ -654,10 +670,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
Log.e("-----", "missing code");
}
/*//////////////////////////////////////////////////////////////////////////
// OwnStack
//////////////////////////////////////////////////////////////////////////*/
private void setupActionBar(final StreamInfo info) {
if (DEBUG) {
Log.d(TAG, "setupActionBarHandler() called with: info = [" + info + "]");
@ -687,7 +699,11 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
});
}
public void pushToStack(final int sid, final String videoUrl, final String title) {
/*//////////////////////////////////////////////////////////////////////////
// OwnStack
//////////////////////////////////////////////////////////////////////////*/
private void pushToStack(final int sid, final String videoUrl, final String title) {
if (DEBUG) {
Log.d(TAG, "pushToStack() called with: serviceId = ["
+ sid + "], videoUrl = [" + videoUrl + "], title = [" + title + "]");
@ -706,7 +722,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
stack.push(new StackItem(sid, videoUrl, title));
}
public void setTitleToUrl(final int sid, final String videoUrl, final String title) {
private void setTitleToUrl(final int sid, final String videoUrl, final String title) {
if (title != null && !title.isEmpty()) {
for (StackItem stackItem : stack) {
if (stack.peek().getServiceId() == sid
@ -755,7 +771,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
prepareAndLoadInfo();
}
public void prepareAndHandleInfo(final StreamInfo info, final boolean scrollToTop) {
private void prepareAndHandleInfo(final StreamInfo info, final boolean scrollToTop) {
if (DEBUG) {
Log.d(TAG, "prepareAndHandleInfo() called with: "
+ "info = [" + info + "], scrollToTop = [" + scrollToTop + "]");
@ -774,7 +790,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
}
protected void prepareAndLoadInfo() {
private void prepareAndLoadInfo() {
appBarLayout.setExpanded(true, true);
pushToStack(serviceId, url, name);
startLoading(false);

View File

@ -44,20 +44,22 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
implements ListViewContract<I, N>, StateSaver.WriteRead,
SharedPreferences.OnSharedPreferenceChangeListener {
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
protected StateSaver.SavedState savedState;
private boolean useDefaultStateSaving = true;
private int updateFlags = 0;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
protected InfoListAdapter infoListAdapter;
protected RecyclerView itemsList;
protected StateSaver.SavedState savedState;
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
private boolean useDefaultStateSaving = true;
private int updateFlags = 0;
@Override
public void onAttach(final Context context) {
@ -81,10 +83,6 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
.registerOnSharedPreferenceChangeListener(this);
}
/*//////////////////////////////////////////////////////////////////////////
// State Saving
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onDestroy() {
super.onDestroy();
@ -111,6 +109,10 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
}
}
/*//////////////////////////////////////////////////////////////////////////
// State Saving
//////////////////////////////////////////////////////////////////////////*/
/**
* If the default implementation of {@link StateSaver.WriteRead} should be used.
*

View File

@ -70,6 +70,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private SubscriptionManager subscriptionManager;
private View headerRootLayout;
private ImageView headerChannelBanner;
@ -83,10 +84,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
private LinearLayout headerBackgroundButton;
private MenuItem menuRssButton;
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
public static ChannelFragment getInstance(final int serviceId, final String url,
final String name) {
ChannelFragment instance = new ChannelFragment();
@ -104,6 +101,10 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
}
}
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onAttach(final Context context) {
super.onAttach(context);
@ -117,10 +118,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
return inflater.inflate(R.layout.fragment_channel, container, false);
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onDestroy() {
super.onDestroy();
@ -133,7 +130,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
// Init
//////////////////////////////////////////////////////////////////////////*/
protected View getListHeader() {
@ -154,6 +151,10 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
return headerRootLayout;
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
@ -179,10 +180,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
}
}
/*//////////////////////////////////////////////////////////////////////////
// Channel Subscription
//////////////////////////////////////////////////////////////////////////*/
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
@ -208,6 +205,10 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Channel Subscription
//////////////////////////////////////////////////////////////////////////*/
private void monitorSubscription(final ChannelInfo info) {
final Consumer<Throwable> onError = (Throwable throwable) -> {
animateView(headerSubscribeButton, false, 100);

View File

@ -294,7 +294,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
}
});
}
} else { // Else say we have no uploader
} else { // Otherwise say we have no uploader
headerUploaderName.setText(R.string.playlist_no_uploader);
}

View File

@ -80,7 +80,6 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage>
implements BackPressable {
/*//////////////////////////////////////////////////////////////////////////
// Search
//////////////////////////////////////////////////////////////////////////*/
@ -97,35 +96,45 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
*/
private static final int SUGGESTIONS_DEBOUNCE = 120; //ms
private final PublishSubject<String> suggestionPublisher = PublishSubject.create();
private final CompositeDisposable disposables = new CompositeDisposable();
@State
protected int filterItemCheckedId = -1;
int filterItemCheckedId = -1;
@State
protected int serviceId = Constants.NO_SERVICE_ID;
// this three represet the current search query
// these three represents the current search query
@State
protected String searchString;
String searchString;
/**
* No content filter should add like contentfilter = all
* No content filter should add like contentFilter = all
* be aware of this when implementing an extractor.
*/
@State
protected String[] contentFilter = new String[0];
String[] contentFilter = new String[0];
@State
protected String sortFilter;
// these represtent the last search
String sortFilter;
// these represents the last search
@State
protected String lastSearchedString;
String lastSearchedString;
@State
protected boolean wasSearchFocused = false;
boolean wasSearchFocused = false;
private Map<Integer, String> menuItemToFilterName;
private StreamingService service;
private String currentPageUrl;
private String nextPageUrl;
private String contentCountry;
private boolean isSuggestionsEnabled = true;
private Disposable searchDisposable;
private Disposable suggestionDisposable;
private final CompositeDisposable disposables = new CompositeDisposable();
private SuggestionListAdapter suggestionListAdapter;
private HistoryRecordManager historyRecordManager;
@ -141,6 +150,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
private RecyclerView suggestionsRecyclerView;
/*////////////////////////////////////////////////////////////////////////*/
private TextWatcher textWatcher;
public static SearchFragment getInstance(final int serviceId, final String searchString) {
@ -154,10 +164,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
return searchFragment;
}
/*//////////////////////////////////////////////////////////////////////////
// Fragment's LifeCycle
//////////////////////////////////////////////////////////////////////////*/
/**
* Set wasLoading to true so when the fragment onResume is called, the initial search is done.
*/
@ -165,6 +171,10 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
wasLoading.set(true);
}
/*//////////////////////////////////////////////////////////////////////////
// Fragment's LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onAttach(final Context context) {
super.onAttach(context);
@ -287,10 +297,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
}
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
@ -310,7 +316,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
}
/*//////////////////////////////////////////////////////////////////////////
// State Saving
// Init
//////////////////////////////////////////////////////////////////////////*/
@Override
@ -344,6 +350,10 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
searchClear = searchToolbarContainer.findViewById(R.id.toolbar_search_clear);
}
/*//////////////////////////////////////////////////////////////////////////
// State Saving
//////////////////////////////////////////////////////////////////////////*/
@Override
public void writeTo(final Queue<Object> objectsToSave) {
super.writeTo(objectsToSave);
@ -358,10 +368,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
nextPageUrl = (String) savedObjects.poll();
}
/*//////////////////////////////////////////////////////////////////////////
// Init's
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onSaveInstanceState(final Bundle bundle) {
searchString = searchEditText != null
@ -371,7 +377,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
// Init's
//////////////////////////////////////////////////////////////////////////*/
@Override
@ -390,6 +396,10 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
}
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
@ -430,10 +440,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Search
//////////////////////////////////////////////////////////////////////////*/
private void restoreFilterChecked(final Menu menu, final int itemId) {
if (itemId != -1) {
MenuItem item = menu.findItem(itemId);
@ -445,6 +451,10 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
}
}
/*//////////////////////////////////////////////////////////////////////////
// Search
//////////////////////////////////////////////////////////////////////////*/
private void showSearchOnStart() {
if (DEBUG) {
Log.d(TAG, "showSearchOnStart() called, searchQuery → "

View File

@ -34,16 +34,15 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
private static final String INFO_KEY = "related_info_key";
private CompositeDisposable disposables = new CompositeDisposable();
private RelatedStreamInfo relatedStreamInfo;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private View headerRootLayout;
private Switch aSwitch;
private boolean mIsVisibleToUser = false;
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
private boolean mIsVisibleToUser = false;
public static RelatedVideosFragment getInstance(final StreamInfo info) {
RelatedVideosFragment instance = new RelatedVideosFragment();
@ -57,6 +56,10 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
mIsVisibleToUser = isVisibleToUser;
}
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onAttach(final Context context) {
super.onAttach(context);
@ -141,10 +144,6 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
}
}
/*//////////////////////////////////////////////////////////////////////////
// OnError
//////////////////////////////////////////////////////////////////////////*/
@Override
public void handleNextItems(final ListExtractor.InfoItemsPage result) {
super.handleNextItems(result);
@ -159,7 +158,7 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
// OnError
//////////////////////////////////////////////////////////////////////////*/
@Override
@ -174,6 +173,10 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
@Override
public void setTitle(final String title) {
return;

View File

@ -92,10 +92,6 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
return inflater.inflate(R.layout.fragment_bookmarks, container, false);
}
///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Views
///////////////////////////////////////////////////////////////////////////
@Override
public void setUserVisibleHint(final boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
@ -104,15 +100,15 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
}
}
///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Views
///////////////////////////////////////////////////////////////////////////
@Override
protected void initViews(final View rootView, final Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
}
///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Loading
///////////////////////////////////////////////////////////////////////////
@Override
protected void initListeners() {
super.initListeners();
@ -149,7 +145,7 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
}
///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Destruction
// Fragment LifeCycle - Loading
///////////////////////////////////////////////////////////////////////////
@Override
@ -163,6 +159,10 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
.subscribe(getPlaylistsSubscriber());
}
///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Destruction
///////////////////////////////////////////////////////////////////////////
@Override
public void onPause() {
super.onPause();
@ -183,10 +183,6 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
databaseSubscription = null;
}
///////////////////////////////////////////////////////////////////////////
// Subscriptions Loader
///////////////////////////////////////////////////////////////////////////
@Override
public void onDestroy() {
super.onDestroy();
@ -200,6 +196,10 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
itemsListState = null;
}
///////////////////////////////////////////////////////////////////////////
// Subscriptions Loader
///////////////////////////////////////////////////////////////////////////
private Subscriber<List<PlaylistLocalItem>> getPlaylistsSubscriber() {
return new Subscriber<List<PlaylistLocalItem>>() {
@Override
@ -229,9 +229,6 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
public void onComplete() { }
};
}
///////////////////////////////////////////////////////////////////////////
// Fragment Error Handling
///////////////////////////////////////////////////////////////////////////
@Override
public void handleResult(@NonNull final List<PlaylistLocalItem> result) {
@ -252,6 +249,10 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
hideLoading();
}
///////////////////////////////////////////////////////////////////////////
// Fragment Error Handling
///////////////////////////////////////////////////////////////////////////
@Override
protected boolean onError(final Throwable exception) {
if (super.onError(exception)) {
@ -263,10 +264,6 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
return true;
}
///////////////////////////////////////////////////////////////////////////
// Utils
///////////////////////////////////////////////////////////////////////////
@Override
protected void resetFragment() {
super.resetFragment();
@ -275,6 +272,10 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
}
}
///////////////////////////////////////////////////////////////////////////
// Utils
///////////////////////////////////////////////////////////////////////////
private void showRemoteDeleteDialog(final PlaylistRemoteEntity item) {
showDeleteDialog(item.getName(), remotePlaylistManager.deletePlaylist(item.getUid()));
}

View File

@ -80,16 +80,16 @@ public class StatisticsPlaylistFragment
}
}
///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Creation
///////////////////////////////////////////////////////////////////////////
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
recordManager = new HistoryRecordManager(getContext());
}
///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Creation
///////////////////////////////////////////////////////////////////////////
@Override
public View onCreateView(@NonNull final LayoutInflater inflater,
@Nullable final ViewGroup container,
@ -111,6 +111,10 @@ public class StatisticsPlaylistFragment
inflater.inflate(R.menu.menu_history, menu);
}
///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Views
///////////////////////////////////////////////////////////////////////////
@Override
protected void initViews(final View rootView, final Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
@ -119,10 +123,6 @@ public class StatisticsPlaylistFragment
}
}
///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Views
///////////////////////////////////////////////////////////////////////////
@Override
protected View getListHeader() {
final View headerRootLayout = activity.getLayoutInflater()
@ -210,6 +210,10 @@ public class StatisticsPlaylistFragment
return true;
}
///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Loading
///////////////////////////////////////////////////////////////////////////
@Override
public void startLoading(final boolean forceLoad) {
super.startLoading(forceLoad);
@ -219,7 +223,7 @@ public class StatisticsPlaylistFragment
}
///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Loading
// Fragment LifeCycle - Destruction
///////////////////////////////////////////////////////////////////////////
@Override
@ -228,10 +232,6 @@ public class StatisticsPlaylistFragment
itemsListState = itemsList.getLayoutManager().onSaveInstanceState();
}
///////////////////////////////////////////////////////////////////////////
// Fragment LifeCycle - Destruction
///////////////////////////////////////////////////////////////////////////
@Override
public void onDestroyView() {
super.onDestroyView();
@ -262,6 +262,10 @@ public class StatisticsPlaylistFragment
itemsListState = null;
}
///////////////////////////////////////////////////////////////////////////
// Statistics Loader
///////////////////////////////////////////////////////////////////////////
private Subscriber<List<StreamStatisticsEntry>> getHistoryObserver() {
return new Subscriber<List<StreamStatisticsEntry>>() {
@Override
@ -294,10 +298,6 @@ public class StatisticsPlaylistFragment
};
}
///////////////////////////////////////////////////////////////////////////
// Statistics Loader
///////////////////////////////////////////////////////////////////////////
@Override
public void handleResult(@NonNull final List<StreamStatisticsEntry> result) {
super.handleResult(result);
@ -331,6 +331,10 @@ public class StatisticsPlaylistFragment
hideLoading();
}
///////////////////////////////////////////////////////////////////////////
// Fragment Error Handling
///////////////////////////////////////////////////////////////////////////
@Override
protected void resetFragment() {
super.resetFragment();
@ -338,9 +342,6 @@ public class StatisticsPlaylistFragment
databaseSubscription.cancel();
}
}
///////////////////////////////////////////////////////////////////////////
// Fragment Error Handling
///////////////////////////////////////////////////////////////////////////
@Override
protected boolean onError(final Throwable exception) {
@ -353,6 +354,10 @@ public class StatisticsPlaylistFragment
return true;
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
private void toggleSortMode() {
if (sortMode == StatisticSortMode.LAST_PLAYED) {
sortMode = StatisticSortMode.MOST_PLAYED;
@ -370,10 +375,6 @@ public class StatisticsPlaylistFragment
startLoading(true);
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
private PlayQueue getPlayQueueStartingAt(final StreamStatisticsEntry infoItem) {
return getPlayQueue(Math.max(itemListAdapter.getItemsList().indexOf(infoItem), 0));
}

View File

@ -56,12 +56,14 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
// Save the list 10 seconds after the last change occurred
private static final long SAVE_DEBOUNCE_MILLIS = 10000;
private static final int MINIMUM_INITIAL_DRAG_VELOCITY = 12;
@State
protected Long playlistId;
@State
protected String name;
@State
protected Parcelable itemsListState;
Parcelable itemsListState;
private View headerRootLayout;
private TextView headerTitleView;
private TextView headerStreamCount;

View File

@ -47,18 +47,20 @@ public class SubscriptionsImportFragment extends BaseFragment {
private static final int REQUEST_IMPORT_FILE_CODE = 666;
@State
protected int currentServiceId = Constants.NO_SERVICE_ID;
int currentServiceId = Constants.NO_SERVICE_ID;
private List<SubscriptionExtractor.ContentSource> supportedSources;
private String relatedUrl;
@StringRes
private int instructionsString;
private TextView infoTextView;
private EditText inputText;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private TextView infoTextView;
private EditText inputText;
private Button inputButton;
public static SubscriptionsImportFragment getInstance(final int serviceId) {
@ -67,7 +69,7 @@ public class SubscriptionsImportFragment extends BaseFragment {
return instance;
}
public void setInitialData(final int serviceId) {
private void setInitialData(final int serviceId) {
this.currentServiceId = serviceId;
}

View File

@ -53,9 +53,16 @@ import io.reactivex.processors.PublishProcessor;
public abstract class BaseImportExportService extends Service {
protected final String TAG = this.getClass().getSimpleName();
private static final int NOTIFICATION_SAMPLING_PERIOD = 2500;
protected final CompositeDisposable disposables = new CompositeDisposable();
protected final PublishProcessor<String> notificationUpdater = PublishProcessor.create();
protected NotificationManagerCompat notificationManager;
protected NotificationCompat.Builder notificationBuilder;
protected SubscriptionManager subscriptionManager;
private static final int NOTIFICATION_SAMPLING_PERIOD = 2500;
protected final AtomicInteger currentProgress = new AtomicInteger(-1);
protected final AtomicInteger maxProgress = new AtomicInteger(-1);
protected final ImportExportEventListener eventListener = new ImportExportEventListener() {
@ -71,13 +78,7 @@ public abstract class BaseImportExportService extends Service {
notificationUpdater.onNext(itemName);
}
};
protected NotificationManagerCompat notificationManager;
protected NotificationCompat.Builder notificationBuilder;
protected SubscriptionManager subscriptionManager;
/*//////////////////////////////////////////////////////////////////////////
// Notification Impl
//////////////////////////////////////////////////////////////////////////*/
protected Toast toast;
@Nullable
@ -103,6 +104,10 @@ public abstract class BaseImportExportService extends Service {
disposables.clear();
}
/*//////////////////////////////////////////////////////////////////////////
// Notification Impl
//////////////////////////////////////////////////////////////////////////*/
protected abstract int getNotificationId();
@StringRes

View File

@ -67,15 +67,18 @@ public class SubscriptionsImportService extends BaseImportExportService {
*/
public static final String IMPORT_COMPLETE_ACTION = "org.schabi.newpipe.local.subscription"
+ ".services.SubscriptionsImportService.IMPORT_COMPLETE";
/**
* How many extractions running in parallel.
*/
public static final int PARALLEL_EXTRACTIONS = 8;
/**
* Number of items to buffer to mass-insert in the subscriptions table,
* this leads to a better performance as we can then use db transactions.
*/
public static final int BUFFER_COUNT_BEFORE_INSERT = 50;
private Subscription subscription;
private int currentMode;
private int currentServiceId;
@ -131,10 +134,6 @@ public class SubscriptionsImportService extends BaseImportExportService {
return 4568;
}
/*//////////////////////////////////////////////////////////////////////////
// Imports
//////////////////////////////////////////////////////////////////////////*/
@Override
public int getTitle() {
return R.string.import_ongoing;
@ -148,6 +147,10 @@ public class SubscriptionsImportService extends BaseImportExportService {
}
}
/*//////////////////////////////////////////////////////////////////////////
// Imports
//////////////////////////////////////////////////////////////////////////*/
private void startImport() {
showToast(R.string.import_ongoing);

View File

@ -99,10 +99,22 @@ import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK_ADJ
@SuppressWarnings({"WeakerAccess"})
public abstract class BasePlayer implements
Player.EventListener, PlaybackListener, ImageLoadingListener {
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
@NonNull
public static final String TAG = "BasePlayer";
public static final int STATE_PREFLIGHT = -1;
public static final int STATE_BLOCKED = 123;
public static final int STATE_PLAYING = 124;
public static final int STATE_BUFFERING = 125;
public static final int STATE_PAUSED = 126;
public static final int STATE_PAUSED_SEEK = 127;
public static final int STATE_COMPLETED = 128;
/*//////////////////////////////////////////////////////////////////////////
// Intent
//////////////////////////////////////////////////////////////////////////*/
@NonNull
public static final String REPEAT_MODE = "repeat_mode";
@NonNull
@ -123,26 +135,43 @@ public abstract class BasePlayer implements
public static final String START_PAUSED = "start_paused";
@NonNull
public static final String SELECT_ON_APPEND = "select_on_append";
/*//////////////////////////////////////////////////////////////////////////
// Intent
//////////////////////////////////////////////////////////////////////////*/
@NonNull
public static final String IS_MUTED = "is_muted";
public static final int STATE_PREFLIGHT = -1;
public static final int STATE_BLOCKED = 123;
public static final int STATE_PLAYING = 124;
public static final int STATE_BUFFERING = 125;
public static final int STATE_PAUSED = 126;
public static final int STATE_PAUSED_SEEK = 127;
public static final int STATE_COMPLETED = 128;
protected static final float[] PLAYBACK_SPEEDS = {0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f};
protected static final int PLAY_PREV_ACTIVATION_LIMIT_MILLIS = 5000; // 5 seconds
protected static final int PROGRESS_LOOP_INTERVAL_MILLIS = 500;
/*//////////////////////////////////////////////////////////////////////////
// Playback
//////////////////////////////////////////////////////////////////////////*/
protected static final int RECOVERY_SKIP_THRESHOLD_MILLIS = 3000; // 3 seconds
protected static final float[] PLAYBACK_SPEEDS = {0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f};
protected PlayQueue playQueue;
protected PlayQueueAdapter playQueueAdapter;
@Nullable
protected MediaSourceManager playbackManager;
@Nullable
private PlayQueueItem currentItem;
@Nullable
private MediaSourceTag currentMetadata;
@Nullable
private Bitmap currentThumbnail;
@Nullable
protected Toast errorToast;
/*//////////////////////////////////////////////////////////////////////////
// Player
//////////////////////////////////////////////////////////////////////////*/
protected static final int PLAY_PREV_ACTIVATION_LIMIT_MILLIS = 5000; // 5 seconds
protected static final int PROGRESS_LOOP_INTERVAL_MILLIS = 500;
protected SimpleExoPlayer simpleExoPlayer;
protected AudioReactor audioReactor;
protected MediaSessionManager mediaSessionManager;
@NonNull
protected final Context context;
@NonNull
@ -158,39 +187,17 @@ public abstract class BasePlayer implements
@NonNull
private final LoadControl loadControl;
/*//////////////////////////////////////////////////////////////////////////
// Player
//////////////////////////////////////////////////////////////////////////*/
@NonNull
private final RenderersFactory renderFactory;
@NonNull
private final SerialDisposable progressUpdateReactor;
@NonNull
private final CompositeDisposable databaseUpdateReactor;
protected PlayQueue playQueue;
protected PlayQueueAdapter playQueueAdapter;
@Nullable
protected MediaSourceManager playbackManager;
@Nullable
protected Toast errorToast;
protected SimpleExoPlayer simpleExoPlayer;
//////////////////////////////////////////////////////////////////////////*/
protected AudioReactor audioReactor;
protected MediaSessionManager mediaSessionManager;
protected int currentState = STATE_PREFLIGHT;
@Nullable
private PlayQueueItem currentItem;
@Nullable
private MediaSourceTag currentMetadata;
@Nullable
private Bitmap currentThumbnail;
private boolean isPrepared = false;
private Disposable stateLoader;
/*//////////////////////////////////////////////////////////////////////////
// Thumbnail Loading
//////////////////////////////////////////////////////////////////////////*/
protected int currentState = STATE_PREFLIGHT;
public BasePlayer(@NonNull final Context context) {
this.context = context;
@ -247,8 +254,7 @@ public abstract class BasePlayer implements
registerBroadcastReceiver();
}
public void initListeners() {
}
public void initListeners() { }
public void handleIntent(final Intent intent) {
if (DEBUG) {
@ -324,10 +330,6 @@ public abstract class BasePlayer implements
/*playOnInit=*/!intent.getBooleanExtra(START_PAUSED, false), isMuted);
}
/*//////////////////////////////////////////////////////////////////////////
// Broadcast Receiver
//////////////////////////////////////////////////////////////////////////*/
protected void initPlayback(@NonNull final PlayQueue queue,
@Player.RepeatMode final int repeatMode,
final float playbackSpeed,
@ -398,9 +400,12 @@ public abstract class BasePlayer implements
databaseUpdateReactor.clear();
progressUpdateReactor.set(null);
}
/*//////////////////////////////////////////////////////////////////////////
// Thumbnail Loading
//////////////////////////////////////////////////////////////////////////*/
private void initThumbnail(final String url) {
if (DEBUG) {
Log.d(TAG, "Thumbnail - initThumbnail() called");
@ -413,10 +418,6 @@ public abstract class BasePlayer implements
.loadImage(url, ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, this);
}
/*//////////////////////////////////////////////////////////////////////////
// States Implementation
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onLoadingStarted(final String imageUri, final View view) {
if (DEBUG) {
@ -453,6 +454,10 @@ public abstract class BasePlayer implements
currentThumbnail = null;
}
/*//////////////////////////////////////////////////////////////////////////
// Broadcast Receiver
//////////////////////////////////////////////////////////////////////////*/
/**
* Add your action in the intentFilter.
*
@ -488,6 +493,10 @@ public abstract class BasePlayer implements
}
}
/*//////////////////////////////////////////////////////////////////////////
// States Implementation
//////////////////////////////////////////////////////////////////////////*/
public void changeState(final int state) {
if (DEBUG) {
Log.d(TAG, "changeState() called with: state = [" + state + "]");
@ -1328,6 +1337,7 @@ public abstract class BasePlayer implements
playQueue.append(autoQueue.getStreams());
}
}
/*//////////////////////////////////////////////////////////////////////////
// Getters and Setters
//////////////////////////////////////////////////////////////////////////*/

View File

@ -1181,11 +1181,14 @@ public final class MainVideoPlayer extends AppCompatActivity
private class PlayerGestureListener extends GestureDetector.SimpleOnGestureListener
implements View.OnTouchListener {
private static final int MOVEMENT_THRESHOLD = 40;
private final boolean isVolumeGestureEnabled = PlayerHelper
.isVolumeGestureEnabled(getApplicationContext());
private final boolean isBrightnessGestureEnabled = PlayerHelper
.isBrightnessGestureEnabled(getApplicationContext());
private final int maxVolume = playerImpl.getAudioReactor().getMaxVolume();
private boolean isMoving;
@Override

View File

@ -54,14 +54,19 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
View.OnClickListener, PlaybackParameterDialog.Callback {
private static final int RECYCLER_ITEM_POPUP_MENU_GROUP_ID = 47;
private static final int SMOOTH_SCROLL_MAXIMUM_DISTANCE = 80;
protected BasePlayer player;
private boolean serviceBound;
private ServiceConnection serviceConnection;
private boolean seeking;
private boolean redraw;
////////////////////////////////////////////////////////////////////////////
// Views
////////////////////////////////////////////////////////////////////////////
private boolean seeking;
private boolean redraw;
private View rootView;
private RecyclerView itemsList;

View File

@ -90,51 +90,69 @@ public abstract class VideoPlayer extends BasePlayer
Player.EventListener,
PopupMenu.OnMenuItemClickListener,
PopupMenu.OnDismissListener {
public final String TAG;
public static final boolean DEBUG = BasePlayer.DEBUG;
public static final int DEFAULT_CONTROLS_DURATION = 300; // 300 millis
/*//////////////////////////////////////////////////////////////////////////
// Player
//////////////////////////////////////////////////////////////////////////*/
public static final int DEFAULT_CONTROLS_DURATION = 300; // 300 millis
public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000; // 2 Seconds
protected static final int RENDERER_UNAVAILABLE = -1;
public final String TAG;
@NonNull
private final VideoPlaybackResolver resolver;
private final Handler controlsVisibilityHandler = new Handler();
private final int qualityPopupMenuGroupId = 69;
private final int playbackSpeedPopupMenuGroupId = 79;
private List<VideoStream> availableStreams;
private int selectedStreamIndex;
protected boolean wasPlaying = false;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
private final int captionPopupMenuGroupId = 89;
protected boolean wasPlaying = false;
boolean isSomePopupMenuVisible = false;
private List<VideoStream> availableStreams;
private int selectedStreamIndex;
private View rootView;
private AspectRatioFrameLayout aspectRatioFrameLayout;
private SurfaceView surfaceView;
private View surfaceForeground;
private View loadingPanel;
private ImageView endScreen;
private ImageView controlAnimationView;
private View controlsRoot;
private TextView currentDisplaySeek;
private View bottomControlsRoot;
private SeekBar playbackSeekBar;
private TextView playbackCurrentTime;
private TextView playbackEndTime;
private TextView playbackLiveSync;
private TextView playbackSpeedTextView;
private View topControlsRoot;
private TextView qualityTextView;
private SubtitleView subtitleView;
private TextView resizeView;
private TextView captionTextView;
private ValueAnimator controlViewAnimator;
private final Handler controlsVisibilityHandler = new Handler();
boolean isSomePopupMenuVisible = false;
private final int qualityPopupMenuGroupId = 69;
private PopupMenu qualityPopupMenu;
private final int playbackSpeedPopupMenuGroupId = 79;
private PopupMenu playbackSpeedPopupMenu;
private final int captionPopupMenuGroupId = 89;
private PopupMenu captionPopupMenu;
///////////////////////////////////////////////////////////////////////////
@ -238,10 +256,6 @@ public abstract class VideoPlayer extends BasePlayer
}
}
/*//////////////////////////////////////////////////////////////////////////
// UI Builders
//////////////////////////////////////////////////////////////////////////*/
@Override
public void handleIntent(final Intent intent) {
if (intent == null) {
@ -255,6 +269,10 @@ public abstract class VideoPlayer extends BasePlayer
super.handleIntent(intent);
}
/*//////////////////////////////////////////////////////////////////////////
// UI Builders
//////////////////////////////////////////////////////////////////////////*/
public void buildQualityMenu() {
if (qualityPopupMenu == null) {
return;
@ -354,9 +372,6 @@ public abstract class VideoPlayer extends BasePlayer
}
captionPopupMenu.setOnDismissListener(this);
}
/*//////////////////////////////////////////////////////////////////////////
// Playback Listener
//////////////////////////////////////////////////////////////////////////*/
private void updateStreamRelatedViews() {
if (getCurrentMetadata() == null) {
@ -413,6 +428,10 @@ public abstract class VideoPlayer extends BasePlayer
playbackSpeedTextView.setVisibility(View.VISIBLE);
}
/*//////////////////////////////////////////////////////////////////////////
// Playback Listener
//////////////////////////////////////////////////////////////////////////*/
protected abstract VideoPlaybackResolver.QualityResolver getQualityResolver();
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
@ -420,16 +439,16 @@ public abstract class VideoPlayer extends BasePlayer
updateStreamRelatedViews();
}
/*//////////////////////////////////////////////////////////////////////////
// States Implementation
//////////////////////////////////////////////////////////////////////////*/
@Override
@Nullable
public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) {
return resolver.resolve(info);
}
/*//////////////////////////////////////////////////////////////////////////
// States Implementation
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onBlocked() {
super.onBlocked();
@ -494,10 +513,6 @@ public abstract class VideoPlayer extends BasePlayer
showAndAnimateControl(-1, true);
}
/*//////////////////////////////////////////////////////////////////////////
// ExoPlayer Video Listener
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCompleted() {
super.onCompleted();
@ -510,6 +525,10 @@ public abstract class VideoPlayer extends BasePlayer
animateView(surfaceForeground, true, 100);
}
/*//////////////////////////////////////////////////////////////////////////
// ExoPlayer Video Listener
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onTracksChanged(final TrackGroupArray trackGroups,
final TrackSelectionArray trackSelections) {
@ -537,15 +556,15 @@ public abstract class VideoPlayer extends BasePlayer
aspectRatioFrameLayout.setAspectRatio(((float) width) / height);
}
/*//////////////////////////////////////////////////////////////////////////
// ExoPlayer Track Updates
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onRenderedFirstFrame() {
animateView(surfaceForeground, false, 100);
}
/*//////////////////////////////////////////////////////////////////////////
// ExoPlayer Track Updates
//////////////////////////////////////////////////////////////////////////*/
private void onTextTrackUpdate() {
final int textRenderer = getRendererIndex(C.TRACK_TYPE_TEXT);

View File

@ -20,17 +20,20 @@ import java.io.File;
/* package-private */ class CacheFactory implements DataSource.Factory {
private static final String TAG = "CacheFactory";
private static final String CACHE_FOLDER_NAME = "exoplayer";
private static final int CACHE_FLAGS = CacheDataSource.FLAG_BLOCK_ON_CACHE
| CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR;
private final DefaultDataSourceFactory dataSourceFactory;
private final File cacheDir;
private final long maxFileSize;
// Creating cache on every instance may cause problems with multiple players when
// sources are not ExtractorMediaSource
// see: https://stackoverflow.com/questions/28700391/using-cache-in-exoplayer
// todo: make this a singleton?
private static SimpleCache cache;
private final DefaultDataSourceFactory dataSourceFactory;
private final File cacheDir;
private final long maxFileSize;
CacheFactory(@NonNull final Context context,
@NonNull final String userAgent,

View File

@ -23,19 +23,23 @@ import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
public class PlaybackParameterDialog extends DialogFragment {
// Minimum allowable range in ExoPlayer
public static final double MINIMUM_PLAYBACK_VALUE = 0.10f;
public static final double MAXIMUM_PLAYBACK_VALUE = 3.00f;
public static final char STEP_UP_SIGN = '+';
public static final char STEP_DOWN_SIGN = '-';
public static final double STEP_ONE_PERCENT_VALUE = 0.01f;
public static final double STEP_FIVE_PERCENT_VALUE = 0.05f;
public static final double STEP_TEN_PERCENT_VALUE = 0.10f;
public static final double STEP_TWENTY_FIVE_PERCENT_VALUE = 0.25f;
public static final double STEP_ONE_HUNDRED_PERCENT_VALUE = 1.00f;
public static final double DEFAULT_TEMPO = 1.00f;
public static final double DEFAULT_PITCH = 1.00f;
public static final double DEFAULT_STEP = STEP_TWENTY_FIVE_PERCENT_VALUE;
public static final boolean DEFAULT_SKIP_SILENCE = false;
private static final double MINIMUM_PLAYBACK_VALUE = 0.10f;
private static final double MAXIMUM_PLAYBACK_VALUE = 3.00f;
private static final char STEP_UP_SIGN = '+';
private static final char STEP_DOWN_SIGN = '-';
private static final double STEP_ONE_PERCENT_VALUE = 0.01f;
private static final double STEP_FIVE_PERCENT_VALUE = 0.05f;
private static final double STEP_TEN_PERCENT_VALUE = 0.10f;
private static final double STEP_TWENTY_FIVE_PERCENT_VALUE = 0.25f;
private static final double STEP_ONE_HUNDRED_PERCENT_VALUE = 1.00f;
private static final double DEFAULT_TEMPO = 1.00f;
private static final double DEFAULT_PITCH = 1.00f;
private static final double DEFAULT_STEP = STEP_TWENTY_FIVE_PERCENT_VALUE;
private static final boolean DEFAULT_SKIP_SILENCE = false;
@NonNull
private static final String TAG = "PlaybackParameterDialog";
@NonNull
@ -49,18 +53,22 @@ public class PlaybackParameterDialog extends DialogFragment {
private static final String PITCH_KEY = "pitch_key";
@NonNull
private static final String STEP_SIZE_KEY = "step_size_key";
@NonNull
private final SliderStrategy strategy = new SliderStrategy.Quadratic(
MINIMUM_PLAYBACK_VALUE, MAXIMUM_PLAYBACK_VALUE,
/*centerAt=*/1.00f, /*sliderGranularity=*/10000);
@Nullable
private Callback callback;
private double initialTempo = DEFAULT_TEMPO;
private double initialPitch = DEFAULT_PITCH;
private boolean initialSkipSilence = DEFAULT_SKIP_SILENCE;
private double tempo = DEFAULT_TEMPO;
private double pitch = DEFAULT_PITCH;
private double stepSize = DEFAULT_STEP;
@Nullable
private SeekBar tempoSlider;
@Nullable
@ -96,25 +104,10 @@ public class PlaybackParameterDialog extends DialogFragment {
return dialog;
}
@NonNull
private static String getStepUpPercentString(final double percent) {
return STEP_UP_SIGN + getPercentString(percent);
}
/*//////////////////////////////////////////////////////////////////////////
// Lifecycle
//////////////////////////////////////////////////////////////////////////*/
@NonNull
private static String getStepDownPercentString(final double percent) {
return STEP_DOWN_SIGN + getPercentString(percent);
}
@NonNull
private static String getPercentString(final double percent) {
return PlayerHelper.formatPitch(percent);
}
@Override
public void onAttach(final Context context) {
super.onAttach(context);
@ -125,10 +118,6 @@ public class PlaybackParameterDialog extends DialogFragment {
}
}
/*//////////////////////////////////////////////////////////////////////////
// Dialog
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
assureCorrectAppLanguage(getContext());
@ -143,10 +132,6 @@ public class PlaybackParameterDialog extends DialogFragment {
}
}
/*//////////////////////////////////////////////////////////////////////////
// Control Views
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
@ -158,6 +143,10 @@ public class PlaybackParameterDialog extends DialogFragment {
outState.putDouble(STEP_SIZE_KEY, getCurrentStepSize());
}
/*//////////////////////////////////////////////////////////////////////////
// Dialog
//////////////////////////////////////////////////////////////////////////*/
@NonNull
@Override
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
@ -179,6 +168,10 @@ public class PlaybackParameterDialog extends DialogFragment {
return dialogBuilder.create();
}
/*//////////////////////////////////////////////////////////////////////////
// Control Views
//////////////////////////////////////////////////////////////////////////*/
private void setupControlViews(@NonNull final View rootView) {
setupHookingControl(rootView);
setupSkipSilenceControl(rootView);
@ -273,10 +266,6 @@ public class PlaybackParameterDialog extends DialogFragment {
}
}
/*//////////////////////////////////////////////////////////////////////////
// Sliders
//////////////////////////////////////////////////////////////////////////*/
private void setupStepSizeSelector(@NonNull final View rootView) {
TextView stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent);
TextView stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent);
@ -355,6 +344,10 @@ public class PlaybackParameterDialog extends DialogFragment {
}
}
/*//////////////////////////////////////////////////////////////////////////
// Sliders
//////////////////////////////////////////////////////////////////////////*/
private SeekBar.OnSeekBarChangeListener getOnTempoChangedListener() {
return new SeekBar.OnSeekBarChangeListener() {
@Override
@ -430,10 +423,6 @@ public class PlaybackParameterDialog extends DialogFragment {
setPitchSlider(newValue);
}
/*//////////////////////////////////////////////////////////////////////////
// Helper
//////////////////////////////////////////////////////////////////////////*/
private void setTempoSlider(final double newTempo) {
if (tempoSlider == null) {
return;
@ -448,6 +437,10 @@ public class PlaybackParameterDialog extends DialogFragment {
pitchSlider.setProgress(strategy.progressOf(newPitch));
}
/*//////////////////////////////////////////////////////////////////////////
// Helper
//////////////////////////////////////////////////////////////////////////*/
private void setCurrentPlaybackParameters() {
setPlaybackParameters(getCurrentTempo(), getCurrentPitch(), getCurrentSkipSilence());
}
@ -483,6 +476,21 @@ public class PlaybackParameterDialog extends DialogFragment {
return skipSilenceCheckbox != null && skipSilenceCheckbox.isChecked();
}
@NonNull
private static String getStepUpPercentString(final double percent) {
return STEP_UP_SIGN + getPercentString(percent);
}
@NonNull
private static String getStepDownPercentString(final double percent) {
return STEP_DOWN_SIGN + getPercentString(percent);
}
@NonNull
private static String getPercentString(final double percent) {
return PlayerHelper.formatPitch(percent);
}
public interface Callback {
void onPlaybackParameterChanged(float playbackTempo, float playbackPitch,
boolean playbackSkipSilence);

View File

@ -58,6 +58,10 @@ public final class PlayerHelper {
private PlayerHelper() { }
////////////////////////////////////////////////////////////////////////////
// Exposed helpers
////////////////////////////////////////////////////////////////////////////
public static String getTimeString(final int milliSeconds) {
int seconds = (milliSeconds % 60000) / 1000;
int minutes = (milliSeconds % 3600000) / 60000;
@ -72,9 +76,6 @@ public final class PlayerHelper {
? STRING_FORMATTER.format("%d:%02d:%02d", hours, minutes, seconds).toString()
: STRING_FORMATTER.format("%02d:%02d", minutes, seconds).toString();
}
////////////////////////////////////////////////////////////////////////////
// Exposed helpers
////////////////////////////////////////////////////////////////////////////
public static String formatSpeed(final double speed) {
return SPEED_FORMATTER.format(speed);
@ -177,14 +178,14 @@ public final class PlayerHelper {
? null : getAutoQueuedSinglePlayQueue(autoQueueItems.get(0));
}
public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) {
return isResumeAfterAudioFocusGain(context, false);
}
////////////////////////////////////////////////////////////////////////////
// Settings Resolution
////////////////////////////////////////////////////////////////////////////
public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) {
return isResumeAfterAudioFocusGain(context, false);
}
public static boolean isVolumeGestureEnabled(@NonNull final Context context) {
return isVolumeGestureEnabled(context, true);
}
@ -322,15 +323,15 @@ public final class PlayerHelper {
setScreenBrightness(context, setScreenBrightness, System.currentTimeMillis());
}
////////////////////////////////////////////////////////////////////////////
// Private helpers
////////////////////////////////////////////////////////////////////////////
@NonNull
private static SharedPreferences getPreferences(@NonNull final Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
////////////////////////////////////////////////////////////////////////////
// Private helpers
////////////////////////////////////////////////////////////////////////////
private static boolean isResumeAfterAudioFocusGain(@NonNull final Context context,
final boolean b) {
return getPreferences(context)

View File

@ -44,16 +44,21 @@ import static org.schabi.newpipe.player.mediasource.FailedMediaSource.StreamInfo
import static org.schabi.newpipe.player.playqueue.PlayQueue.DEBUG;
public class MediaSourceManager {
@NonNull
private final String TAG = "MediaSourceManager@" + hashCode();
/**
* Determines how many streams before and after the current stream should be loaded.
* The default value (1) ensures seamless playback under typical network settings.
* <br><br>
* <p>
* The streams after the current will be loaded into the playlist timeline while the
* streams before will only be cached for future usage.
* </p>
*
* @see #onMediaSourceReceived(PlayQueueItem, ManagedMediaSource)
*/
private static final int WINDOW_SIZE = 1;
/**
* Determines the maximum number of disposables allowed in the {@link #loaderReactor}.
* Once exceeded, new calls to {@link #loadImmediate()} will evict all disposables in the
@ -63,12 +68,12 @@ public class MediaSourceManager {
* @see #maybeLoadItem(PlayQueueItem)
*/
private static final int MAXIMUM_LOADER_SIZE = WINDOW_SIZE * 2 + 1;
@NonNull
private final String TAG = "MediaSourceManager@" + hashCode();
@NonNull
private final PlaybackListener playbackListener;
@NonNull
private final PlayQueue playQueue;
/**
* Determines the gap time between the playback position and the playback duration which
* the {@link #getEdgeIntervalSignal()} begins to request loading.
@ -76,35 +81,45 @@ public class MediaSourceManager {
* @see #progressUpdateIntervalMillis
*/
private final long playbackNearEndGapMillis;
/**
* Determines the interval which the {@link #getEdgeIntervalSignal()} waits for between
* each request for loading, once {@link #playbackNearEndGapMillis} has reached.
*/
private final long progressUpdateIntervalMillis;
@NonNull
private final Observable<Long> nearEndIntervalSignal;
/**
* Process only the last load order when receiving a stream of load orders (lessens I/O).
* <br><br>
* <p>
* The higher it is, the less loading occurs during rapid noncritical timeline changes.
* <br><br>
* </p>
* <p>
* Not recommended to go below 100ms.
* </p>
*
* @see #loadDebounced()
*/
private final long loadDebounceMillis;
@NonNull
private final Disposable debouncedLoader;
@NonNull
private final PublishSubject<Long> debouncedSignal;
@NonNull
private Subscription playQueueReactor;
@NonNull
private final CompositeDisposable loaderReactor;
@NonNull
private final Set<PlayQueueItem> loadingItems;
@NonNull
private final AtomicBoolean isBlocked;
@NonNull
private Subscription playQueueReactor;
@NonNull
private ManagedMediaSourcePlaylist playlist;
@ -160,42 +175,6 @@ public class MediaSourceManager {
// Exposed Methods
//////////////////////////////////////////////////////////////////////////*/
/*//////////////////////////////////////////////////////////////////////////
// Manager Helpers
//////////////////////////////////////////////////////////////////////////*/
@Nullable
private static ItemsToLoad getItemsToLoad(@NonNull final PlayQueue playQueue) {
// The current item has higher priority
final int currentIndex = playQueue.getIndex();
final PlayQueueItem currentItem = playQueue.getItem(currentIndex);
if (currentItem == null) {
return null;
}
// The rest are just for seamless playback
// Although timeline is not updated prior to the current index, these sources are still
// loaded into the cache for faster retrieval at a potentially later time.
final int leftBound = Math.max(0, currentIndex - MediaSourceManager.WINDOW_SIZE);
final int rightLimit = currentIndex + MediaSourceManager.WINDOW_SIZE + 1;
final int rightBound = Math.min(playQueue.size(), rightLimit);
final Set<PlayQueueItem> neighbors = new ArraySet<>(
playQueue.getStreams().subList(leftBound, rightBound));
// Do a round robin
final int excess = rightLimit - playQueue.size();
if (excess >= 0) {
neighbors.addAll(playQueue.getStreams()
.subList(0, Math.min(playQueue.size(), excess)));
}
neighbors.remove(currentItem);
return new ItemsToLoad(currentItem, neighbors);
}
/*//////////////////////////////////////////////////////////////////////////
// Event Reactor
//////////////////////////////////////////////////////////////////////////*/
/**
* Dispose the manager and releases all message buses and loaders.
*/
@ -211,6 +190,10 @@ public class MediaSourceManager {
loaderReactor.dispose();
}
/*//////////////////////////////////////////////////////////////////////////
// Event Reactor
//////////////////////////////////////////////////////////////////////////*/
private Subscriber<PlayQueueEvent> getReactor() {
return new Subscriber<PlayQueueEvent>() {
@Override
@ -233,10 +216,6 @@ public class MediaSourceManager {
};
}
/*//////////////////////////////////////////////////////////////////////////
// Playback Locking
//////////////////////////////////////////////////////////////////////////*/
private void onPlayQueueChanged(final PlayQueueEvent event) {
if (playQueue.isEmpty() && playQueue.isComplete()) {
playbackListener.onPlaybackShutdown();
@ -298,6 +277,10 @@ public class MediaSourceManager {
playQueueReactor.request(1);
}
/*//////////////////////////////////////////////////////////////////////////
// Playback Locking
//////////////////////////////////////////////////////////////////////////*/
private boolean isPlayQueueReady() {
final boolean isWindowLoaded = playQueue.size() - playQueue.getIndex() > WINDOW_SIZE;
return playQueue.isComplete() || isWindowLoaded;
@ -332,10 +315,6 @@ public class MediaSourceManager {
isBlocked.set(true);
}
/*//////////////////////////////////////////////////////////////////////////
// Metadata Synchronization
//////////////////////////////////////////////////////////////////////////*/
private void maybeUnblock() {
if (DEBUG) {
Log.d(TAG, "maybeUnblock() called.");
@ -347,6 +326,10 @@ public class MediaSourceManager {
}
}
/*//////////////////////////////////////////////////////////////////////////
// Metadata Synchronization
//////////////////////////////////////////////////////////////////////////*/
private void maybeSync() {
if (DEBUG) {
Log.d(TAG, "maybeSync() called.");
@ -360,10 +343,6 @@ public class MediaSourceManager {
playbackListener.onPlaybackSynchronize(currentItem);
}
/*//////////////////////////////////////////////////////////////////////////
// MediaSource Loading
//////////////////////////////////////////////////////////////////////////*/
private synchronized void maybeSynchronizePlayer() {
if (isPlayQueueReady() && isPlaybackReady()) {
maybeUnblock();
@ -371,6 +350,10 @@ public class MediaSourceManager {
}
}
/*//////////////////////////////////////////////////////////////////////////
// MediaSource Loading
//////////////////////////////////////////////////////////////////////////*/
private Observable<Long> getEdgeIntervalSignal() {
return Observable.interval(progressUpdateIntervalMillis, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
@ -523,9 +506,6 @@ public class MediaSourceManager {
}
playlist.invalidate(currentIndex, removeMediaSourceHandler, this::loadImmediate);
}
/*//////////////////////////////////////////////////////////////////////////
// MediaSource Playlist Helpers
//////////////////////////////////////////////////////////////////////////*/
private void maybeClearLoaders() {
if (DEBUG) {
@ -538,6 +518,10 @@ public class MediaSourceManager {
}
}
/*//////////////////////////////////////////////////////////////////////////
// MediaSource Playlist Helpers
//////////////////////////////////////////////////////////////////////////*/
private void resetSources() {
if (DEBUG) {
Log.d(TAG, "resetSources() called.");
@ -554,6 +538,39 @@ public class MediaSourceManager {
}
}
/*//////////////////////////////////////////////////////////////////////////
// Manager Helpers
//////////////////////////////////////////////////////////////////////////*/
@Nullable
private static ItemsToLoad getItemsToLoad(@NonNull final PlayQueue playQueue) {
// The current item has higher priority
final int currentIndex = playQueue.getIndex();
final PlayQueueItem currentItem = playQueue.getItem(currentIndex);
if (currentItem == null) {
return null;
}
// The rest are just for seamless playback
// Although timeline is not updated prior to the current index, these sources are still
// loaded into the cache for faster retrieval at a potentially later time.
final int leftBound = Math.max(0, currentIndex - MediaSourceManager.WINDOW_SIZE);
final int rightLimit = currentIndex + MediaSourceManager.WINDOW_SIZE + 1;
final int rightBound = Math.min(playQueue.size(), rightLimit);
final Set<PlayQueueItem> neighbors = new ArraySet<>(
playQueue.getStreams().subList(leftBound, rightBound));
// Do a round robin
final int excess = rightLimit - playQueue.size();
if (excess >= 0) {
neighbors.addAll(playQueue.getStreams()
.subList(0, Math.min(playQueue.size(), excess)));
}
neighbors.remove(currentItem);
return new ItemsToLoad(currentItem, neighbors);
}
private static class ItemsToLoad {
@NonNull
private final PlayQueueItem center;

View File

@ -16,10 +16,11 @@ import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
abstract class AbstractInfoPlayQueue<T extends ListInfo, U extends InfoItem> extends PlayQueue {
final int serviceId;
final String baseUrl;
boolean isInitial;
private boolean isComplete;
final int serviceId;
final String baseUrl;
String nextUrl;
private transient Disposable fetchReactor;
@ -40,16 +41,6 @@ abstract class AbstractInfoPlayQueue<T extends ListInfo, U extends InfoItem> ext
this.isComplete = !isInitial && (nextPageUrl == null || nextPageUrl.isEmpty());
}
private static List<PlayQueueItem> extractListItems(final List<StreamInfoItem> infos) {
List<PlayQueueItem> result = new ArrayList<>();
for (final InfoItem stream : infos) {
if (stream instanceof StreamInfoItem) {
result.add(new PlayQueueItem((StreamInfoItem) stream));
}
}
return result;
}
protected abstract String getTag();
@Override
@ -134,4 +125,14 @@ abstract class AbstractInfoPlayQueue<T extends ListInfo, U extends InfoItem> ext
}
fetchReactor = null;
}
private static List<PlayQueueItem> extractListItems(final List<StreamInfoItem> infos) {
List<PlayQueueItem> result = new ArrayList<>();
for (final InfoItem stream : infos) {
if (stream instanceof StreamInfoItem) {
result.add(new PlayQueueItem((StreamInfoItem) stream));
}
}
return result;
}
}

View File

@ -36,17 +36,22 @@ import io.reactivex.subjects.BehaviorSubject;
* <p>
* This class contains basic manipulation of a playlist while also functions as a
* message bus, providing all listeners with new updates to the play queue.
* </p>
* <p>
* This class can be serialized for passing intents, but in order to start the
* message bus, it must be initialized.
* </p>
*/
public abstract class PlayQueue implements Serializable {
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
private final String TAG = "PlayQueue@" + Integer.toHexString(hashCode());
@NonNull
private final AtomicInteger queueIndex;
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
private ArrayList<PlayQueueItem> backup;
private ArrayList<PlayQueueItem> streams;
@NonNull
private final AtomicInteger queueIndex;
private transient BehaviorSubject<PlayQueueEvent> eventBroadcast;
private transient Flowable<PlayQueueEvent> broadcastReceiver;
private transient Subscription reportingReactor;

View File

@ -28,19 +28,23 @@ import io.reactivex.disposables.Disposable;
* <p>
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
* InfoListAdapter.java is part of NewPipe.
* </p>
* <p>
* NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* </p>
* <p>
* NewPipe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* </p>
* <p>
* You should have received a copy of the GNU General Public License
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
* </p>
*/
public class PlayQueueAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

View File

@ -32,6 +32,7 @@ public class VideoPlaybackResolver implements PlaybackResolver {
private final PlayerDataSource dataSource;
@NonNull
private final QualityResolver qualityResolver;
@Nullable
private String playbackQuality;

View File

@ -181,25 +181,6 @@ public class ErrorActivity extends AppCompatActivity {
return out;
}
/**
* Get the checked activity.
*
* @param returnActivity the activity to return to
* @return the casted return activity or null
*/
@Nullable
static Class<? extends Activity> getReturnActivity(final Class<?> returnActivity) {
Class<? extends Activity> checkedReturnActivity = null;
if (returnActivity != null) {
if (Activity.class.isAssignableFrom(returnActivity)) {
checkedReturnActivity = returnActivity.asSubclass(Activity.class);
} else {
checkedReturnActivity = MainActivity.class;
}
}
return checkedReturnActivity;
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
assureCorrectAppLanguage(this);
@ -315,6 +296,25 @@ public class ErrorActivity extends AppCompatActivity {
return text.toString();
}
/**
* Get the checked activity.
*
* @param returnActivity the activity to return to
* @return the casted return activity or null
*/
@Nullable
static Class<? extends Activity> getReturnActivity(final Class<?> returnActivity) {
Class<? extends Activity> checkedReturnActivity = null;
if (returnActivity != null) {
if (Activity.class.isAssignableFrom(returnActivity)) {
checkedReturnActivity = returnActivity.asSubclass(Activity.class);
} else {
checkedReturnActivity = MainActivity.class;
}
}
return checkedReturnActivity;
}
private void goToReturnActivity() {
Class<? extends Activity> checkedReturnActivity = getReturnActivity(returnActivity);
if (checkedReturnActivity == null) {

View File

@ -54,17 +54,20 @@ import io.reactivex.schedulers.Schedulers;
public class PeertubeInstanceListFragment extends Fragment {
private static final int MENU_ITEM_RESTORE_ID = 123456;
public InstanceListAdapter instanceListAdapter;
private List<PeertubeInstance> instanceList = new ArrayList<>();
private PeertubeInstance selectedInstance;
private String savedInstanceListKey;
private InstanceListAdapter instanceListAdapter;
private ProgressBar progressBar;
private SharedPreferences sharedPreferences;
private CompositeDisposable disposables = new CompositeDisposable();
/*//////////////////////////////////////////////////////////////////////////
// Lifecycle
//////////////////////////////////////////////////////////////////////////*/
private CompositeDisposable disposables = new CompositeDisposable();
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
@ -122,9 +125,6 @@ public class PeertubeInstanceListFragment extends Fragment {
super.onPause();
saveChanges();
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onDestroy() {
@ -135,6 +135,10 @@ public class PeertubeInstanceListFragment extends Fragment {
disposables = null;
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
@ -284,10 +288,6 @@ public class PeertubeInstanceListFragment extends Fragment {
instanceListAdapter.notifyDataSetChanged();
}
/*//////////////////////////////////////////////////////////////////////////
// List Handling
//////////////////////////////////////////////////////////////////////////*/
private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
return new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
ItemTouchHelper.START | ItemTouchHelper.END) {
@ -348,6 +348,10 @@ public class PeertubeInstanceListFragment extends Fragment {
};
}
/*//////////////////////////////////////////////////////////////////////////
// List Handling
//////////////////////////////////////////////////////////////////////////*/
private class InstanceListAdapter
extends RecyclerView.Adapter<InstanceListAdapter.TabViewHolder> {
private final LayoutInflater inflater;

View File

@ -57,18 +57,18 @@ public class SelectChannelFragment extends DialogFragment {
/**
* This contains the base display options for images.
*/
public static final DisplayImageOptions DISPLAY_IMAGE_OPTIONS
private static final DisplayImageOptions DISPLAY_IMAGE_OPTIONS
= new DisplayImageOptions.Builder().cacheInMemory(true).build();
private final ImageLoader imageLoader = ImageLoader.getInstance();
OnSelectedLisener onSelectedLisener = null;
OnCancelListener onCancelListener = null;
private ProgressBar progressBar;
/*//////////////////////////////////////////////////////////////////////////
// Interfaces
//////////////////////////////////////////////////////////////////////////*/
private final ImageLoader imageLoader = ImageLoader.getInstance();
private OnSelectedLisener onSelectedLisener = null;
private OnCancelListener onCancelListener = null;
private ProgressBar progressBar;
private TextView emptyView;
private RecyclerView recyclerView;
private List<SubscriptionEntity> subscriptions = new Vector<>();
public void setOnSelectedLisener(final OnSelectedLisener listener) {
@ -79,6 +79,10 @@ public class SelectChannelFragment extends DialogFragment {
onCancelListener = listener;
}
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
@Override
public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
final Bundle savedInstanceState) {
@ -105,7 +109,7 @@ public class SelectChannelFragment extends DialogFragment {
}
/*//////////////////////////////////////////////////////////////////////////
// Init
// Handle actions
//////////////////////////////////////////////////////////////////////////*/
@Override
@ -116,11 +120,6 @@ public class SelectChannelFragment extends DialogFragment {
}
}
/*//////////////////////////////////////////////////////////////////////////
// Handle actions
//////////////////////////////////////////////////////////////////////////*/
private void clickedItem(final int position) {
if (onSelectedLisener != null) {
SubscriptionEntity entry = subscriptions.get(position);
@ -130,6 +129,10 @@ public class SelectChannelFragment extends DialogFragment {
dismiss();
}
/*//////////////////////////////////////////////////////////////////////////
// Item handling
//////////////////////////////////////////////////////////////////////////*/
private void displayChannels(final List<SubscriptionEntity> newSubscriptions) {
this.subscriptions = newSubscriptions;
progressBar.setVisibility(View.GONE);
@ -141,10 +144,6 @@ public class SelectChannelFragment extends DialogFragment {
}
/*//////////////////////////////////////////////////////////////////////////
// Item handling
//////////////////////////////////////////////////////////////////////////*/
private Observer<List<SubscriptionEntity>> getSubscriptionObserver() {
return new Observer<List<SubscriptionEntity>>() {
@Override
@ -165,29 +164,28 @@ public class SelectChannelFragment extends DialogFragment {
};
}
/*//////////////////////////////////////////////////////////////////////////
// Error
//////////////////////////////////////////////////////////////////////////*/
protected void onError(final Throwable e) {
final Activity activity = getActivity();
ErrorActivity.reportError(activity, e, activity.getClass(), null, ErrorActivity.ErrorInfo
.make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash));
}
/*//////////////////////////////////////////////////////////////////////////
// Interfaces
//////////////////////////////////////////////////////////////////////////*/
public interface OnSelectedLisener {
void onChannelSelected(int serviceId, String url, String name);
}
/*//////////////////////////////////////////////////////////////////////////
// Error
//////////////////////////////////////////////////////////////////////////*/
public interface OnCancelListener {
void onCancel();
}
/*//////////////////////////////////////////////////////////////////////////
// ImageLoaderOptions
//////////////////////////////////////////////////////////////////////////*/
private class SelectChannelAdapter
extends RecyclerView.Adapter<SelectChannelAdapter.SelectChannelItemHolder> {
@Override
@ -219,8 +217,8 @@ public class SelectChannelFragment extends DialogFragment {
public class SelectChannelItemHolder extends RecyclerView.ViewHolder {
public final View view;
public final CircleImageView thumbnailView;
public final TextView titleView;
final CircleImageView thumbnailView;
final TextView titleView;
SelectChannelItemHolder(final View v) {
super(v);
this.view = v;

View File

@ -50,9 +50,6 @@ public class SelectKioskFragment extends DialogFragment {
private RecyclerView recyclerView = null;
private SelectKioskAdapter selectKioskAdapter = null;
/*//////////////////////////////////////////////////////////////////////////
// Interfaces
//////////////////////////////////////////////////////////////////////////*/
private OnSelectedLisener onSelectedLisener = null;
private OnCancelListener onCancelListener = null;
@ -80,6 +77,10 @@ public class SelectKioskFragment extends DialogFragment {
return v;
}
/*//////////////////////////////////////////////////////////////////////////
// Handle actions
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCancel(final DialogInterface dialogInterface) {
super.onCancel(dialogInterface);
@ -95,8 +96,8 @@ public class SelectKioskFragment extends DialogFragment {
dismiss();
}
/*//////////////////////////////////////////////////////////////////////////
// Handle actions
/*//////////////////////////////////////////////////////////////////////////
// Error
//////////////////////////////////////////////////////////////////////////*/
protected void onError(final Throwable e) {
@ -105,6 +106,10 @@ public class SelectKioskFragment extends DialogFragment {
.make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash));
}
/*//////////////////////////////////////////////////////////////////////////
// Interfaces
//////////////////////////////////////////////////////////////////////////*/
public interface OnSelectedLisener {
void onKioskSelected(int serviceId, String kioskId, String kioskName);
}
@ -113,10 +118,6 @@ public class SelectKioskFragment extends DialogFragment {
void onCancel();
}
/*//////////////////////////////////////////////////////////////////////////
// Error
//////////////////////////////////////////////////////////////////////////*/
private class SelectKioskAdapter
extends RecyclerView.Adapter<SelectKioskAdapter.SelectKioskItemHolder> {
private final List<Entry> kioskList = new Vector<>();

View File

@ -45,10 +45,11 @@ import static org.schabi.newpipe.settings.tabs.Tab.typeFrom;
public class ChooseTabsFragment extends Fragment {
private static final int MENU_ITEM_RESTORE_ID = 123456;
private ChooseTabsFragment.SelectedTabsAdapter selectedTabsAdapter;
private TabsManager tabsManager;
private List<Tab> tabList = new ArrayList<>();
private ChooseTabsFragment.SelectedTabsAdapter selectedTabsAdapter;
/*//////////////////////////////////////////////////////////////////////////
// Lifecycle
@ -93,16 +94,16 @@ public class ChooseTabsFragment extends Fragment {
updateTitle();
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onPause() {
super.onPause();
saveChanges();
}
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
@ -216,7 +217,7 @@ public class ChooseTabsFragment extends Fragment {
}
}
public ChooseTabListItem[] getAvailableTabs(final Context context) {
private ChooseTabListItem[] getAvailableTabs(final Context context) {
final ArrayList<ChooseTabListItem> returnList = new ArrayList<>();
for (Tab.Type type : Tab.Type.values()) {

View File

@ -39,6 +39,10 @@ public abstract class Tab {
readDataFromJson(jsonObject);
}
/*//////////////////////////////////////////////////////////////////////////
// Tab Handling
//////////////////////////////////////////////////////////////////////////*/
@Nullable
public static Tab from(@NonNull final JsonObject jsonObject) {
final int tabId = jsonObject.getInt(Tab.JSON_TAB_ID_KEY, -1);
@ -85,10 +89,6 @@ public abstract class Tab {
return type.getTab();
}
/*//////////////////////////////////////////////////////////////////////////
// JSON Handling
//////////////////////////////////////////////////////////////////////////*/
public abstract int getTabId();
public abstract String getTabName(Context context);
@ -104,10 +104,6 @@ public abstract class Tab {
*/
public abstract Fragment getFragment(Context context) throws ExtractionException;
/*//////////////////////////////////////////////////////////////////////////
// Tab Handling
//////////////////////////////////////////////////////////////////////////*/
@Override
public boolean equals(final Object obj) {
if (obj == this) {
@ -118,6 +114,10 @@ public abstract class Tab {
&& ((Tab) obj).getTabId() == this.getTabId();
}
/*//////////////////////////////////////////////////////////////////////////
// JSON Handling
//////////////////////////////////////////////////////////////////////////*/
public void writeJsonOn(final JsonSink jsonSink) {
jsonSink.object();

View File

@ -41,10 +41,6 @@ public final class TabsManager {
sharedPreferences.edit().putString(savedTabsKey, jsonToSave).apply();
}
/*//////////////////////////////////////////////////////////////////////////
// Listener
//////////////////////////////////////////////////////////////////////////*/
public void resetTabs() {
sharedPreferences.edit().remove(savedTabsKey).apply();
}
@ -53,6 +49,10 @@ public final class TabsManager {
return TabsJsonHelper.getDefaultTabs();
}
/*//////////////////////////////////////////////////////////////////////////
// Listener
//////////////////////////////////////////////////////////////////////////*/
public void setSavedTabsListener(final SavedTabsChangeListener listener) {
if (preferenceChangeListener != null) {
sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
@ -83,12 +83,4 @@ public final class TabsManager {
public interface SavedTabsChangeListener {
void onTabsChanged();
}
}

View File

@ -32,18 +32,20 @@ import org.schabi.newpipe.extractor.InfoItem;
import java.util.Map;
public final class InfoCache {
private final String TAG = getClass().getSimpleName();
private static final boolean DEBUG = MainActivity.DEBUG;
private static final InfoCache INSTANCE = new InfoCache();
private static final int MAX_ITEMS_ON_CACHE = 60;
/**
* Trim the cache to this size.
*/
private static final int TRIM_CACHE_TO = 30;
private static final LruCache<String, CacheData> LRU_CACHE = new LruCache<>(MAX_ITEMS_ON_CACHE);
private final String TAG = getClass().getSimpleName();
private InfoCache() {
//no instance
// no instance
}
public static InfoCache getInstance() {

View File

@ -47,26 +47,26 @@ import static org.schabi.newpipe.MainActivity.DEBUG;
* A view that can be fully collapsed and expanded.
*/
public class CollapsibleView extends LinearLayout {
private static final String TAG = CollapsibleView.class.getSimpleName();
private static final int ANIMATION_DURATION = 420;
public static final int COLLAPSED = 0;
public static final int EXPANDED = 1;
private static final String TAG = CollapsibleView.class.getSimpleName();
private static final int ANIMATION_DURATION = 420;
private final List<StateListener> listeners = new ArrayList<>();
@State
@ViewMode
int currentState = COLLAPSED;
/*//////////////////////////////////////////////////////////////////////////
// Collapse/expand logic
//////////////////////////////////////////////////////////////////////////*/
private boolean readyToChangeState;
private int targetHeight = -1;
private ValueAnimator currentAnimator;
private final List<StateListener> listeners = new ArrayList<>();
public CollapsibleView(final Context context) {
super(context);
}
public CollapsibleView(final Context context, @Nullable final AttributeSet attrs) {
super(context, attrs);
}
@ -75,12 +75,17 @@ public class CollapsibleView extends LinearLayout {
final int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public CollapsibleView(final Context context, final AttributeSet attrs, final int defStyleAttr,
final int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
/*//////////////////////////////////////////////////////////////////////////
// Collapse/expand logic
//////////////////////////////////////////////////////////////////////////*/
/**
* This method recalculates the height of this view so it <b>must</b> be called when
* some child changes (e.g. add new views, change text).
@ -198,6 +203,10 @@ public class CollapsibleView extends LinearLayout {
listeners.remove(listener);
}
/*//////////////////////////////////////////////////////////////////////////
// State Saving
//////////////////////////////////////////////////////////////////////////*/
@Nullable
@Override
public Parcelable onSaveInstanceState() {
@ -212,7 +221,7 @@ public class CollapsibleView extends LinearLayout {
}
/*//////////////////////////////////////////////////////////////////////////
// State Saving
// Internal
//////////////////////////////////////////////////////////////////////////*/
public String getDebugLogString(final String description) {
@ -226,12 +235,7 @@ public class CollapsibleView extends LinearLayout {
@Retention(SOURCE)
@IntDef({COLLAPSED, EXPANDED})
public @interface ViewMode {
}
/*//////////////////////////////////////////////////////////////////////////
// Internal
//////////////////////////////////////////////////////////////////////////*/
public @interface ViewMode { }
/**
* Simple interface used for listening state changes of the {@link CollapsibleView}.