Move things back to its original place
This commit is contained in:
parent
fda5405e48
commit
63bcc04eff
|
@ -204,7 +204,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
||||||
*
|
*
|
||||||
* @param versionName Name of new version
|
* @param versionName Name of new version
|
||||||
* @param apkLocationUrl Url with the new apk
|
* @param apkLocationUrl Url with the new apk
|
||||||
* @param versionCode V
|
* @param versionCode Code of new version
|
||||||
*/
|
*/
|
||||||
private void compareAppVersionAndShowNotification(final String versionName,
|
private void compareAppVersionAndShowNotification(final String versionName,
|
||||||
final String apkLocationUrl,
|
final String apkLocationUrl,
|
||||||
|
|
|
@ -86,35 +86,41 @@ public class DownloadDialog extends DialogFragment
|
||||||
private static final String TAG = "DialogFragment";
|
private static final String TAG = "DialogFragment";
|
||||||
private static final boolean DEBUG = MainActivity.DEBUG;
|
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
private static final int REQUEST_DOWNLOAD_SAVE_AS = 0x1230;
|
private static final int REQUEST_DOWNLOAD_SAVE_AS = 0x1230;
|
||||||
private final CompositeDisposable disposables = new CompositeDisposable();
|
|
||||||
@State
|
@State
|
||||||
protected StreamInfo currentInfo;
|
StreamInfo currentInfo;
|
||||||
@State
|
@State
|
||||||
protected StreamSizeWrapper<AudioStream> wrappedAudioStreams = StreamSizeWrapper.empty();
|
StreamSizeWrapper<AudioStream> wrappedAudioStreams = StreamSizeWrapper.empty();
|
||||||
@State
|
@State
|
||||||
protected StreamSizeWrapper<VideoStream> wrappedVideoStreams = StreamSizeWrapper.empty();
|
StreamSizeWrapper<VideoStream> wrappedVideoStreams = StreamSizeWrapper.empty();
|
||||||
@State
|
@State
|
||||||
protected StreamSizeWrapper<SubtitlesStream> wrappedSubtitleStreams = StreamSizeWrapper.empty();
|
StreamSizeWrapper<SubtitlesStream> wrappedSubtitleStreams = StreamSizeWrapper.empty();
|
||||||
@State
|
@State
|
||||||
protected int selectedVideoIndex = 0;
|
int selectedVideoIndex = 0;
|
||||||
@State
|
@State
|
||||||
protected int selectedAudioIndex = 0;
|
int selectedAudioIndex = 0;
|
||||||
@State
|
@State
|
||||||
protected int selectedSubtitleIndex = 0;
|
int selectedSubtitleIndex = 0;
|
||||||
|
|
||||||
private StoredDirectoryHelper mainStorageAudio = null;
|
private StoredDirectoryHelper mainStorageAudio = null;
|
||||||
private StoredDirectoryHelper mainStorageVideo = null;
|
private StoredDirectoryHelper mainStorageVideo = null;
|
||||||
private DownloadManager downloadManager = null;
|
private DownloadManager downloadManager = null;
|
||||||
private ActionMenuItemView okButton = null;
|
private ActionMenuItemView okButton = null;
|
||||||
private Context context;
|
private Context context;
|
||||||
private boolean askForSavePath;
|
private boolean askForSavePath;
|
||||||
|
|
||||||
private StreamItemAdapter<AudioStream, Stream> audioStreamsAdapter;
|
private StreamItemAdapter<AudioStream, Stream> audioStreamsAdapter;
|
||||||
private StreamItemAdapter<VideoStream, AudioStream> videoStreamsAdapter;
|
private StreamItemAdapter<VideoStream, AudioStream> videoStreamsAdapter;
|
||||||
private StreamItemAdapter<SubtitlesStream, Stream> subtitleStreamsAdapter;
|
private StreamItemAdapter<SubtitlesStream, Stream> subtitleStreamsAdapter;
|
||||||
|
|
||||||
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
|
||||||
private EditText nameEditText;
|
private EditText nameEditText;
|
||||||
private Spinner streamsSpinner;
|
private Spinner streamsSpinner;
|
||||||
private RadioGroup radioStreamsGroup;
|
private RadioGroup radioStreamsGroup;
|
||||||
private TextView threadsCountTextView;
|
private TextView threadsCountTextView;
|
||||||
private SeekBar threadsSeekBar;
|
private SeekBar threadsSeekBar;
|
||||||
|
|
||||||
private SharedPreferences prefs;
|
private SharedPreferences prefs;
|
||||||
|
|
||||||
public static DownloadDialog newInstance(final StreamInfo info) {
|
public static DownloadDialog newInstance(final StreamInfo info) {
|
||||||
|
|
|
@ -109,54 +109,55 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
implements BackPressable, SharedPreferences.OnSharedPreferenceChangeListener,
|
implements BackPressable, SharedPreferences.OnSharedPreferenceChangeListener,
|
||||||
View.OnClickListener, View.OnLongClickListener {
|
View.OnClickListener, View.OnLongClickListener {
|
||||||
public static final String AUTO_PLAY = "auto_play";
|
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 RELATED_STREAMS_UPDATE_FLAG = 0x1;
|
||||||
private static final int RESOLUTIONS_MENU_UPDATE_FLAG = 0x2;
|
private static final int RESOLUTIONS_MENU_UPDATE_FLAG = 0x2;
|
||||||
private static final int TOOLBAR_ITEMS_UPDATE_FLAG = 0x4;
|
private static final int TOOLBAR_ITEMS_UPDATE_FLAG = 0x4;
|
||||||
private static final int COMMENTS_UPDATE_FLAG = 0x8;
|
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 boolean autoPlayEnabled;
|
||||||
private static final String EMPTY_TAB_TAG = "EMPTY TAB";
|
private boolean showRelatedStreams;
|
||||||
private static final String INFO_KEY = "info_key";
|
private boolean showComments;
|
||||||
private static final String STACK_KEY = "stack_key";
|
private String selectedTabTag;
|
||||||
/**
|
|
||||||
* Stack that contains the "navigation history".<br>
|
|
||||||
* The peek is the current video.
|
|
||||||
*/
|
|
||||||
private final LinkedList<StackItem> stack = new LinkedList<>();
|
|
||||||
@State
|
@State
|
||||||
protected int serviceId = Constants.NO_SERVICE_ID;
|
protected int serviceId = Constants.NO_SERVICE_ID;
|
||||||
@State
|
@State
|
||||||
protected String name;
|
protected String name;
|
||||||
@State
|
@State
|
||||||
protected String url;
|
protected String url;
|
||||||
private int updateFlags = 0;
|
|
||||||
private boolean autoPlayEnabled;
|
|
||||||
private boolean showRelatedStreams;
|
|
||||||
private boolean showComments;
|
|
||||||
private String selectedTabTag;
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Views
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
private StreamInfo currentInfo;
|
private StreamInfo currentInfo;
|
||||||
private Disposable currentWorker;
|
private Disposable currentWorker;
|
||||||
@NonNull
|
@NonNull
|
||||||
private CompositeDisposable disposables = new CompositeDisposable();
|
private CompositeDisposable disposables = new CompositeDisposable();
|
||||||
@Nullable
|
@Nullable
|
||||||
private Disposable positionSubscriber = null;
|
private Disposable positionSubscriber = null;
|
||||||
|
|
||||||
private List<VideoStream> sortedVideoStreams;
|
private List<VideoStream> sortedVideoStreams;
|
||||||
private int selectedVideoStreamIndex = -1;
|
private int selectedVideoStreamIndex = -1;
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Views
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private Menu menu;
|
private Menu menu;
|
||||||
|
|
||||||
private Spinner spinnerToolbar;
|
private Spinner spinnerToolbar;
|
||||||
|
|
||||||
private LinearLayout contentRootLayoutHiding;
|
private LinearLayout contentRootLayoutHiding;
|
||||||
|
|
||||||
private View thumbnailBackgroundButton;
|
private View thumbnailBackgroundButton;
|
||||||
private ImageView thumbnailImageView;
|
private ImageView thumbnailImageView;
|
||||||
private ImageView thumbnailPlayButton;
|
private ImageView thumbnailPlayButton;
|
||||||
private AnimatedProgressBar positionView;
|
private AnimatedProgressBar positionView;
|
||||||
|
|
||||||
private View videoTitleRoot;
|
private View videoTitleRoot;
|
||||||
private TextView videoTitleTextView;
|
private TextView videoTitleTextView;
|
||||||
private ImageView videoTitleToggleArrow;
|
private ImageView videoTitleToggleArrow;
|
||||||
private TextView videoCountView;
|
private TextView videoCountView;
|
||||||
|
|
||||||
private TextView detailControlsBackground;
|
private TextView detailControlsBackground;
|
||||||
private TextView detailControlsPopup;
|
private TextView detailControlsPopup;
|
||||||
private TextView detailControlsAddToPlaylist;
|
private TextView detailControlsAddToPlaylist;
|
||||||
|
@ -164,30 +165,42 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
private TextView appendControlsDetail;
|
private TextView appendControlsDetail;
|
||||||
private TextView detailDurationView;
|
private TextView detailDurationView;
|
||||||
private TextView detailPositionView;
|
private TextView detailPositionView;
|
||||||
|
|
||||||
private LinearLayout videoDescriptionRootLayout;
|
private LinearLayout videoDescriptionRootLayout;
|
||||||
private TextView videoUploadDateView;
|
private TextView videoUploadDateView;
|
||||||
private TextView videoDescriptionView;
|
private TextView videoDescriptionView;
|
||||||
|
|
||||||
private View uploaderRootLayout;
|
private View uploaderRootLayout;
|
||||||
private TextView uploaderTextView;
|
private TextView uploaderTextView;
|
||||||
private ImageView uploaderThumb;
|
private ImageView uploaderThumb;
|
||||||
|
|
||||||
private TextView thumbsUpTextView;
|
private TextView thumbsUpTextView;
|
||||||
private ImageView thumbsUpImageView;
|
private ImageView thumbsUpImageView;
|
||||||
private TextView thumbsDownTextView;
|
private TextView thumbsDownTextView;
|
||||||
private ImageView thumbsDownImageView;
|
private ImageView thumbsDownImageView;
|
||||||
private TextView thumbsDisabledTextView;
|
private TextView thumbsDisabledTextView;
|
||||||
|
|
||||||
private AppBarLayout appBarLayout;
|
private AppBarLayout appBarLayout;
|
||||||
private ViewPager viewPager;
|
private ViewPager viewPager;
|
||||||
|
|
||||||
|
|
||||||
/*////////////////////////////////////////////////////////////////////////*/
|
|
||||||
private TabAdaptor pageAdapter;
|
private TabAdaptor pageAdapter;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Fragment's Lifecycle
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
private TabLayout tabLayout;
|
private TabLayout tabLayout;
|
||||||
private FrameLayout relatedStreamsLayout;
|
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,
|
public static VideoDetailFragment getInstance(final int serviceId, final String videoUrl,
|
||||||
final String name) {
|
final String name) {
|
||||||
VideoDetailFragment instance = new VideoDetailFragment();
|
VideoDetailFragment instance = new VideoDetailFragment();
|
||||||
|
@ -195,6 +208,11 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment's Lifecycle
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(final Bundle savedInstanceState) {
|
public void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -285,10 +303,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
disposables = null;
|
disposables = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// State Saving
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -336,6 +350,10 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// State Saving
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(final Bundle outState) {
|
public void onSaveInstanceState(final Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
|
@ -351,10 +369,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
outState.putSerializable(STACK_KEY, stack);
|
outState.putSerializable(STACK_KEY, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// OnClick
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(@NonNull final Bundle savedState) {
|
protected void onRestoreInstanceState(@NonNull final Bundle savedState) {
|
||||||
super.onRestoreInstanceState(savedState);
|
super.onRestoreInstanceState(savedState);
|
||||||
|
@ -371,9 +385,12 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
stack.addAll((Collection<? extends StackItem>) serializable);
|
stack.addAll((Collection<? extends StackItem>) serializable);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// OnClick
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final View v) {
|
public void onClick(final View v) {
|
||||||
if (isLoading.get() || currentInfo == null) {
|
if (isLoading.get() || currentInfo == null) {
|
||||||
|
@ -449,10 +466,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Init
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void toggleTitleAndDescription() {
|
private void toggleTitleAndDescription() {
|
||||||
if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
|
if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
|
||||||
videoTitleTextView.setMaxLines(1);
|
videoTitleTextView.setMaxLines(1);
|
||||||
|
@ -465,6 +478,10 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Init
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
||||||
super.initViews(rootView, savedInstanceState);
|
super.initViews(rootView, savedInstanceState);
|
||||||
|
@ -553,11 +570,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Menu
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void initThumbnailViews(@NonNull final StreamInfo info) {
|
private void initThumbnailViews(@NonNull final StreamInfo info) {
|
||||||
thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
|
thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
|
||||||
if (!TextUtils.isEmpty(info.getThumbnailUrl())) {
|
if (!TextUtils.isEmpty(info.getThumbnailUrl())) {
|
||||||
|
@ -581,6 +593,10 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Menu
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(final Menu m, final MenuInflater inflater) {
|
public void onCreateOptionsMenu(final Menu m, final MenuInflater inflater) {
|
||||||
this.menu = m;
|
this.menu = m;
|
||||||
|
@ -654,10 +670,6 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
Log.e("-----", "missing code");
|
Log.e("-----", "missing code");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// OwnStack
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void setupActionBar(final StreamInfo info) {
|
private void setupActionBar(final StreamInfo info) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "setupActionBarHandler() called with: info = [" + info + "]");
|
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) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "pushToStack() called with: serviceId = ["
|
Log.d(TAG, "pushToStack() called with: serviceId = ["
|
||||||
+ sid + "], videoUrl = [" + videoUrl + "], title = [" + title + "]");
|
+ sid + "], videoUrl = [" + videoUrl + "], title = [" + title + "]");
|
||||||
|
@ -706,7 +722,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
stack.push(new StackItem(sid, videoUrl, title));
|
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()) {
|
if (title != null && !title.isEmpty()) {
|
||||||
for (StackItem stackItem : stack) {
|
for (StackItem stackItem : stack) {
|
||||||
if (stack.peek().getServiceId() == sid
|
if (stack.peek().getServiceId() == sid
|
||||||
|
@ -755,7 +771,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
prepareAndLoadInfo();
|
prepareAndLoadInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prepareAndHandleInfo(final StreamInfo info, final boolean scrollToTop) {
|
private void prepareAndHandleInfo(final StreamInfo info, final boolean scrollToTop) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "prepareAndHandleInfo() called with: "
|
Log.d(TAG, "prepareAndHandleInfo() called with: "
|
||||||
+ "info = [" + info + "], scrollToTop = [" + scrollToTop + "]");
|
+ "info = [" + info + "], scrollToTop = [" + scrollToTop + "]");
|
||||||
|
@ -774,7 +790,7 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void prepareAndLoadInfo() {
|
private void prepareAndLoadInfo() {
|
||||||
appBarLayout.setExpanded(true, true);
|
appBarLayout.setExpanded(true, true);
|
||||||
pushToStack(serviceId, url, name);
|
pushToStack(serviceId, url, name);
|
||||||
startLoading(false);
|
startLoading(false);
|
||||||
|
|
|
@ -44,20 +44,22 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
||||||
implements ListViewContract<I, N>, StateSaver.WriteRead,
|
implements ListViewContract<I, N>, StateSaver.WriteRead,
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
|
||||||
|
protected StateSaver.SavedState savedState;
|
||||||
|
|
||||||
|
private boolean useDefaultStateSaving = true;
|
||||||
|
private int updateFlags = 0;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Views
|
// Views
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
|
|
||||||
protected InfoListAdapter infoListAdapter;
|
protected InfoListAdapter infoListAdapter;
|
||||||
protected RecyclerView itemsList;
|
protected RecyclerView itemsList;
|
||||||
protected StateSaver.SavedState savedState;
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// LifeCycle
|
// LifeCycle
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
private boolean useDefaultStateSaving = true;
|
|
||||||
private int updateFlags = 0;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(final Context context) {
|
public void onAttach(final Context context) {
|
||||||
|
@ -81,10 +83,6 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
||||||
.registerOnSharedPreferenceChangeListener(this);
|
.registerOnSharedPreferenceChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// State Saving
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.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.
|
* If the default implementation of {@link StateSaver.WriteRead} should be used.
|
||||||
*
|
*
|
||||||
|
|
|
@ -70,6 +70,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Views
|
// Views
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private SubscriptionManager subscriptionManager;
|
private SubscriptionManager subscriptionManager;
|
||||||
private View headerRootLayout;
|
private View headerRootLayout;
|
||||||
private ImageView headerChannelBanner;
|
private ImageView headerChannelBanner;
|
||||||
|
@ -83,10 +84,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||||
private LinearLayout headerBackgroundButton;
|
private LinearLayout headerBackgroundButton;
|
||||||
private MenuItem menuRssButton;
|
private MenuItem menuRssButton;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// LifeCycle
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
public static ChannelFragment getInstance(final int serviceId, final String url,
|
public static ChannelFragment getInstance(final int serviceId, final String url,
|
||||||
final String name) {
|
final String name) {
|
||||||
ChannelFragment instance = new ChannelFragment();
|
ChannelFragment instance = new ChannelFragment();
|
||||||
|
@ -104,6 +101,10 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// LifeCycle
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(final Context context) {
|
public void onAttach(final Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
|
@ -117,10 +118,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||||
return inflater.inflate(R.layout.fragment_channel, container, false);
|
return inflater.inflate(R.layout.fragment_channel, container, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Init
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
@ -133,7 +130,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Menu
|
// Init
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected View getListHeader() {
|
protected View getListHeader() {
|
||||||
|
@ -154,6 +151,10 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||||
return headerRootLayout;
|
return headerRootLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Menu
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
@ -179,10 +180,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Channel Subscription
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
|
@ -208,6 +205,10 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Channel Subscription
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void monitorSubscription(final ChannelInfo info) {
|
private void monitorSubscription(final ChannelInfo info) {
|
||||||
final Consumer<Throwable> onError = (Throwable throwable) -> {
|
final Consumer<Throwable> onError = (Throwable throwable) -> {
|
||||||
animateView(headerSubscribeButton, false, 100);
|
animateView(headerSubscribeButton, false, 100);
|
||||||
|
|
|
@ -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);
|
headerUploaderName.setText(R.string.playlist_no_uploader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,6 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage>
|
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage>
|
||||||
implements BackPressable {
|
implements BackPressable {
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Search
|
// Search
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -97,35 +96,45 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
*/
|
*/
|
||||||
private static final int SUGGESTIONS_DEBOUNCE = 120; //ms
|
private static final int SUGGESTIONS_DEBOUNCE = 120; //ms
|
||||||
private final PublishSubject<String> suggestionPublisher = PublishSubject.create();
|
private final PublishSubject<String> suggestionPublisher = PublishSubject.create();
|
||||||
private final CompositeDisposable disposables = new CompositeDisposable();
|
|
||||||
@State
|
@State
|
||||||
protected int filterItemCheckedId = -1;
|
int filterItemCheckedId = -1;
|
||||||
|
|
||||||
@State
|
@State
|
||||||
protected int serviceId = Constants.NO_SERVICE_ID;
|
protected int serviceId = Constants.NO_SERVICE_ID;
|
||||||
// this three represet the current search query
|
|
||||||
|
// these three represents the current search query
|
||||||
@State
|
@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.
|
* be aware of this when implementing an extractor.
|
||||||
*/
|
*/
|
||||||
@State
|
@State
|
||||||
protected String[] contentFilter = new String[0];
|
String[] contentFilter = new String[0];
|
||||||
|
|
||||||
@State
|
@State
|
||||||
protected String sortFilter;
|
String sortFilter;
|
||||||
// these represtent the last search
|
|
||||||
|
// these represents the last search
|
||||||
@State
|
@State
|
||||||
protected String lastSearchedString;
|
String lastSearchedString;
|
||||||
|
|
||||||
@State
|
@State
|
||||||
protected boolean wasSearchFocused = false;
|
boolean wasSearchFocused = false;
|
||||||
|
|
||||||
private Map<Integer, String> menuItemToFilterName;
|
private Map<Integer, String> menuItemToFilterName;
|
||||||
private StreamingService service;
|
private StreamingService service;
|
||||||
private String currentPageUrl;
|
private String currentPageUrl;
|
||||||
private String nextPageUrl;
|
private String nextPageUrl;
|
||||||
private String contentCountry;
|
private String contentCountry;
|
||||||
private boolean isSuggestionsEnabled = true;
|
private boolean isSuggestionsEnabled = true;
|
||||||
|
|
||||||
private Disposable searchDisposable;
|
private Disposable searchDisposable;
|
||||||
private Disposable suggestionDisposable;
|
private Disposable suggestionDisposable;
|
||||||
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
|
||||||
private SuggestionListAdapter suggestionListAdapter;
|
private SuggestionListAdapter suggestionListAdapter;
|
||||||
private HistoryRecordManager historyRecordManager;
|
private HistoryRecordManager historyRecordManager;
|
||||||
|
|
||||||
|
@ -141,6 +150,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
private RecyclerView suggestionsRecyclerView;
|
private RecyclerView suggestionsRecyclerView;
|
||||||
|
|
||||||
/*////////////////////////////////////////////////////////////////////////*/
|
/*////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private TextWatcher textWatcher;
|
private TextWatcher textWatcher;
|
||||||
|
|
||||||
public static SearchFragment getInstance(final int serviceId, final String searchString) {
|
public static SearchFragment getInstance(final int serviceId, final String searchString) {
|
||||||
|
@ -154,10 +164,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
return searchFragment;
|
return searchFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Fragment's LifeCycle
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set wasLoading to true so when the fragment onResume is called, the initial search is done.
|
* 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);
|
wasLoading.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment's LifeCycle
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(final Context context) {
|
public void onAttach(final Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
|
@ -287,10 +297,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Init
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
|
@ -310,7 +316,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// State Saving
|
// Init
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -344,6 +350,10 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
searchClear = searchToolbarContainer.findViewById(R.id.toolbar_search_clear);
|
searchClear = searchToolbarContainer.findViewById(R.id.toolbar_search_clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// State Saving
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(final Queue<Object> objectsToSave) {
|
public void writeTo(final Queue<Object> objectsToSave) {
|
||||||
super.writeTo(objectsToSave);
|
super.writeTo(objectsToSave);
|
||||||
|
@ -358,10 +368,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
nextPageUrl = (String) savedObjects.poll();
|
nextPageUrl = (String) savedObjects.poll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Init's
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(final Bundle bundle) {
|
public void onSaveInstanceState(final Bundle bundle) {
|
||||||
searchString = searchEditText != null
|
searchString = searchEditText != null
|
||||||
|
@ -371,7 +377,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Menu
|
// Init's
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -390,6 +396,10 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Menu
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
@ -430,10 +440,6 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Search
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void restoreFilterChecked(final Menu menu, final int itemId) {
|
private void restoreFilterChecked(final Menu menu, final int itemId) {
|
||||||
if (itemId != -1) {
|
if (itemId != -1) {
|
||||||
MenuItem item = menu.findItem(itemId);
|
MenuItem item = menu.findItem(itemId);
|
||||||
|
@ -445,6 +451,10 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Search
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void showSearchOnStart() {
|
private void showSearchOnStart() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "showSearchOnStart() called, searchQuery → "
|
Log.d(TAG, "showSearchOnStart() called, searchQuery → "
|
||||||
|
|
|
@ -34,16 +34,15 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
|
||||||
private static final String INFO_KEY = "related_info_key";
|
private static final String INFO_KEY = "related_info_key";
|
||||||
private CompositeDisposable disposables = new CompositeDisposable();
|
private CompositeDisposable disposables = new CompositeDisposable();
|
||||||
private RelatedStreamInfo relatedStreamInfo;
|
private RelatedStreamInfo relatedStreamInfo;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Views
|
// Views
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private View headerRootLayout;
|
private View headerRootLayout;
|
||||||
private Switch aSwitch;
|
private Switch aSwitch;
|
||||||
private boolean mIsVisibleToUser = false;
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
private boolean mIsVisibleToUser = false;
|
||||||
// LifeCycle
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
public static RelatedVideosFragment getInstance(final StreamInfo info) {
|
public static RelatedVideosFragment getInstance(final StreamInfo info) {
|
||||||
RelatedVideosFragment instance = new RelatedVideosFragment();
|
RelatedVideosFragment instance = new RelatedVideosFragment();
|
||||||
|
@ -57,6 +56,10 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
|
||||||
mIsVisibleToUser = isVisibleToUser;
|
mIsVisibleToUser = isVisibleToUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// LifeCycle
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(final Context context) {
|
public void onAttach(final Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
|
@ -141,10 +144,6 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// OnError
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleNextItems(final ListExtractor.InfoItemsPage result) {
|
public void handleNextItems(final ListExtractor.InfoItemsPage result) {
|
||||||
super.handleNextItems(result);
|
super.handleNextItems(result);
|
||||||
|
@ -159,7 +158,7 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Utils
|
// OnError
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -174,6 +173,10 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Utils
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTitle(final String title) {
|
public void setTitle(final String title) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -92,10 +92,6 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
return inflater.inflate(R.layout.fragment_bookmarks, container, false);
|
return inflater.inflate(R.layout.fragment_bookmarks, container, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Fragment LifeCycle - Views
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUserVisibleHint(final boolean isVisibleToUser) {
|
public void setUserVisibleHint(final boolean isVisibleToUser) {
|
||||||
super.setUserVisibleHint(isVisibleToUser);
|
super.setUserVisibleHint(isVisibleToUser);
|
||||||
|
@ -104,15 +100,15 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment LifeCycle - Views
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
||||||
super.initViews(rootView, savedInstanceState);
|
super.initViews(rootView, savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Fragment LifeCycle - Loading
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initListeners() {
|
protected void initListeners() {
|
||||||
super.initListeners();
|
super.initListeners();
|
||||||
|
@ -149,7 +145,7 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Fragment LifeCycle - Destruction
|
// Fragment LifeCycle - Loading
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -163,6 +159,10 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
.subscribe(getPlaylistsSubscriber());
|
.subscribe(getPlaylistsSubscriber());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment LifeCycle - Destruction
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
|
@ -183,10 +183,6 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
databaseSubscription = null;
|
databaseSubscription = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Subscriptions Loader
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
@ -200,6 +196,10 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
itemsListState = null;
|
itemsListState = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Subscriptions Loader
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private Subscriber<List<PlaylistLocalItem>> getPlaylistsSubscriber() {
|
private Subscriber<List<PlaylistLocalItem>> getPlaylistsSubscriber() {
|
||||||
return new Subscriber<List<PlaylistLocalItem>>() {
|
return new Subscriber<List<PlaylistLocalItem>>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -229,9 +229,6 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
public void onComplete() { }
|
public void onComplete() { }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Fragment Error Handling
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleResult(@NonNull final List<PlaylistLocalItem> result) {
|
public void handleResult(@NonNull final List<PlaylistLocalItem> result) {
|
||||||
|
@ -252,6 +249,10 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
hideLoading();
|
hideLoading();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment Error Handling
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean onError(final Throwable exception) {
|
protected boolean onError(final Throwable exception) {
|
||||||
if (super.onError(exception)) {
|
if (super.onError(exception)) {
|
||||||
|
@ -263,10 +264,6 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Utils
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void resetFragment() {
|
protected void resetFragment() {
|
||||||
super.resetFragment();
|
super.resetFragment();
|
||||||
|
@ -275,6 +272,10 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Utils
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void showRemoteDeleteDialog(final PlaylistRemoteEntity item) {
|
private void showRemoteDeleteDialog(final PlaylistRemoteEntity item) {
|
||||||
showDeleteDialog(item.getName(), remotePlaylistManager.deletePlaylist(item.getUid()));
|
showDeleteDialog(item.getName(), remotePlaylistManager.deletePlaylist(item.getUid()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,16 +80,16 @@ public class StatisticsPlaylistFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment LifeCycle - Creation
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(final Bundle savedInstanceState) {
|
public void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
recordManager = new HistoryRecordManager(getContext());
|
recordManager = new HistoryRecordManager(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Fragment LifeCycle - Creation
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull final LayoutInflater inflater,
|
public View onCreateView(@NonNull final LayoutInflater inflater,
|
||||||
@Nullable final ViewGroup container,
|
@Nullable final ViewGroup container,
|
||||||
|
@ -111,6 +111,10 @@ public class StatisticsPlaylistFragment
|
||||||
inflater.inflate(R.menu.menu_history, menu);
|
inflater.inflate(R.menu.menu_history, menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment LifeCycle - Views
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
||||||
super.initViews(rootView, savedInstanceState);
|
super.initViews(rootView, savedInstanceState);
|
||||||
|
@ -119,10 +123,6 @@ public class StatisticsPlaylistFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Fragment LifeCycle - Views
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected View getListHeader() {
|
protected View getListHeader() {
|
||||||
final View headerRootLayout = activity.getLayoutInflater()
|
final View headerRootLayout = activity.getLayoutInflater()
|
||||||
|
@ -210,6 +210,10 @@ public class StatisticsPlaylistFragment
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment LifeCycle - Loading
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startLoading(final boolean forceLoad) {
|
public void startLoading(final boolean forceLoad) {
|
||||||
super.startLoading(forceLoad);
|
super.startLoading(forceLoad);
|
||||||
|
@ -219,7 +223,7 @@ public class StatisticsPlaylistFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Fragment LifeCycle - Loading
|
// Fragment LifeCycle - Destruction
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -228,10 +232,6 @@ public class StatisticsPlaylistFragment
|
||||||
itemsListState = itemsList.getLayoutManager().onSaveInstanceState();
|
itemsListState = itemsList.getLayoutManager().onSaveInstanceState();
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Fragment LifeCycle - Destruction
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
|
@ -262,6 +262,10 @@ public class StatisticsPlaylistFragment
|
||||||
itemsListState = null;
|
itemsListState = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Statistics Loader
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private Subscriber<List<StreamStatisticsEntry>> getHistoryObserver() {
|
private Subscriber<List<StreamStatisticsEntry>> getHistoryObserver() {
|
||||||
return new Subscriber<List<StreamStatisticsEntry>>() {
|
return new Subscriber<List<StreamStatisticsEntry>>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -294,10 +298,6 @@ public class StatisticsPlaylistFragment
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Statistics Loader
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleResult(@NonNull final List<StreamStatisticsEntry> result) {
|
public void handleResult(@NonNull final List<StreamStatisticsEntry> result) {
|
||||||
super.handleResult(result);
|
super.handleResult(result);
|
||||||
|
@ -331,6 +331,10 @@ public class StatisticsPlaylistFragment
|
||||||
hideLoading();
|
hideLoading();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment Error Handling
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void resetFragment() {
|
protected void resetFragment() {
|
||||||
super.resetFragment();
|
super.resetFragment();
|
||||||
|
@ -338,9 +342,6 @@ public class StatisticsPlaylistFragment
|
||||||
databaseSubscription.cancel();
|
databaseSubscription.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Fragment Error Handling
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean onError(final Throwable exception) {
|
protected boolean onError(final Throwable exception) {
|
||||||
|
@ -353,6 +354,10 @@ public class StatisticsPlaylistFragment
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Utils
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void toggleSortMode() {
|
private void toggleSortMode() {
|
||||||
if (sortMode == StatisticSortMode.LAST_PLAYED) {
|
if (sortMode == StatisticSortMode.LAST_PLAYED) {
|
||||||
sortMode = StatisticSortMode.MOST_PLAYED;
|
sortMode = StatisticSortMode.MOST_PLAYED;
|
||||||
|
@ -370,10 +375,6 @@ public class StatisticsPlaylistFragment
|
||||||
startLoading(true);
|
startLoading(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Utils
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private PlayQueue getPlayQueueStartingAt(final StreamStatisticsEntry infoItem) {
|
private PlayQueue getPlayQueueStartingAt(final StreamStatisticsEntry infoItem) {
|
||||||
return getPlayQueue(Math.max(itemListAdapter.getItemsList().indexOf(infoItem), 0));
|
return getPlayQueue(Math.max(itemListAdapter.getItemsList().indexOf(infoItem), 0));
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,12 +56,14 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
// Save the list 10 seconds after the last change occurred
|
// Save the list 10 seconds after the last change occurred
|
||||||
private static final long SAVE_DEBOUNCE_MILLIS = 10000;
|
private static final long SAVE_DEBOUNCE_MILLIS = 10000;
|
||||||
private static final int MINIMUM_INITIAL_DRAG_VELOCITY = 12;
|
private static final int MINIMUM_INITIAL_DRAG_VELOCITY = 12;
|
||||||
|
|
||||||
@State
|
@State
|
||||||
protected Long playlistId;
|
protected Long playlistId;
|
||||||
@State
|
@State
|
||||||
protected String name;
|
protected String name;
|
||||||
@State
|
@State
|
||||||
protected Parcelable itemsListState;
|
Parcelable itemsListState;
|
||||||
|
|
||||||
private View headerRootLayout;
|
private View headerRootLayout;
|
||||||
private TextView headerTitleView;
|
private TextView headerTitleView;
|
||||||
private TextView headerStreamCount;
|
private TextView headerStreamCount;
|
||||||
|
|
|
@ -47,18 +47,20 @@ public class SubscriptionsImportFragment extends BaseFragment {
|
||||||
private static final int REQUEST_IMPORT_FILE_CODE = 666;
|
private static final int REQUEST_IMPORT_FILE_CODE = 666;
|
||||||
|
|
||||||
@State
|
@State
|
||||||
protected int currentServiceId = Constants.NO_SERVICE_ID;
|
int currentServiceId = Constants.NO_SERVICE_ID;
|
||||||
|
|
||||||
private List<SubscriptionExtractor.ContentSource> supportedSources;
|
private List<SubscriptionExtractor.ContentSource> supportedSources;
|
||||||
private String relatedUrl;
|
private String relatedUrl;
|
||||||
|
|
||||||
@StringRes
|
@StringRes
|
||||||
private int instructionsString;
|
private int instructionsString;
|
||||||
private TextView infoTextView;
|
|
||||||
private EditText inputText;
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Views
|
// Views
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private TextView infoTextView;
|
||||||
|
private EditText inputText;
|
||||||
private Button inputButton;
|
private Button inputButton;
|
||||||
|
|
||||||
public static SubscriptionsImportFragment getInstance(final int serviceId) {
|
public static SubscriptionsImportFragment getInstance(final int serviceId) {
|
||||||
|
@ -67,7 +69,7 @@ public class SubscriptionsImportFragment extends BaseFragment {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInitialData(final int serviceId) {
|
private void setInitialData(final int serviceId) {
|
||||||
this.currentServiceId = serviceId;
|
this.currentServiceId = serviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,9 +53,16 @@ import io.reactivex.processors.PublishProcessor;
|
||||||
|
|
||||||
public abstract class BaseImportExportService extends Service {
|
public abstract class BaseImportExportService extends Service {
|
||||||
protected final String TAG = this.getClass().getSimpleName();
|
protected final String TAG = this.getClass().getSimpleName();
|
||||||
private static final int NOTIFICATION_SAMPLING_PERIOD = 2500;
|
|
||||||
protected final CompositeDisposable disposables = new CompositeDisposable();
|
protected final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
protected final PublishProcessor<String> notificationUpdater = PublishProcessor.create();
|
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 currentProgress = new AtomicInteger(-1);
|
||||||
protected final AtomicInteger maxProgress = new AtomicInteger(-1);
|
protected final AtomicInteger maxProgress = new AtomicInteger(-1);
|
||||||
protected final ImportExportEventListener eventListener = new ImportExportEventListener() {
|
protected final ImportExportEventListener eventListener = new ImportExportEventListener() {
|
||||||
|
@ -71,13 +78,7 @@ public abstract class BaseImportExportService extends Service {
|
||||||
notificationUpdater.onNext(itemName);
|
notificationUpdater.onNext(itemName);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
protected NotificationManagerCompat notificationManager;
|
|
||||||
protected NotificationCompat.Builder notificationBuilder;
|
|
||||||
protected SubscriptionManager subscriptionManager;
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Notification Impl
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
protected Toast toast;
|
protected Toast toast;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -103,6 +104,10 @@ public abstract class BaseImportExportService extends Service {
|
||||||
disposables.clear();
|
disposables.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Notification Impl
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected abstract int getNotificationId();
|
protected abstract int getNotificationId();
|
||||||
|
|
||||||
@StringRes
|
@StringRes
|
||||||
|
|
|
@ -67,15 +67,18 @@ public class SubscriptionsImportService extends BaseImportExportService {
|
||||||
*/
|
*/
|
||||||
public static final String IMPORT_COMPLETE_ACTION = "org.schabi.newpipe.local.subscription"
|
public static final String IMPORT_COMPLETE_ACTION = "org.schabi.newpipe.local.subscription"
|
||||||
+ ".services.SubscriptionsImportService.IMPORT_COMPLETE";
|
+ ".services.SubscriptionsImportService.IMPORT_COMPLETE";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How many extractions running in parallel.
|
* How many extractions running in parallel.
|
||||||
*/
|
*/
|
||||||
public static final int PARALLEL_EXTRACTIONS = 8;
|
public static final int PARALLEL_EXTRACTIONS = 8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of items to buffer to mass-insert in the subscriptions table,
|
* 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.
|
* this leads to a better performance as we can then use db transactions.
|
||||||
*/
|
*/
|
||||||
public static final int BUFFER_COUNT_BEFORE_INSERT = 50;
|
public static final int BUFFER_COUNT_BEFORE_INSERT = 50;
|
||||||
|
|
||||||
private Subscription subscription;
|
private Subscription subscription;
|
||||||
private int currentMode;
|
private int currentMode;
|
||||||
private int currentServiceId;
|
private int currentServiceId;
|
||||||
|
@ -131,10 +134,6 @@ public class SubscriptionsImportService extends BaseImportExportService {
|
||||||
return 4568;
|
return 4568;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Imports
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTitle() {
|
public int getTitle() {
|
||||||
return R.string.import_ongoing;
|
return R.string.import_ongoing;
|
||||||
|
@ -148,6 +147,10 @@ public class SubscriptionsImportService extends BaseImportExportService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Imports
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void startImport() {
|
private void startImport() {
|
||||||
showToast(R.string.import_ongoing);
|
showToast(R.string.import_ongoing);
|
||||||
|
|
||||||
|
|
|
@ -99,10 +99,22 @@ import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK_ADJ
|
||||||
@SuppressWarnings({"WeakerAccess"})
|
@SuppressWarnings({"WeakerAccess"})
|
||||||
public abstract class BasePlayer implements
|
public abstract class BasePlayer implements
|
||||||
Player.EventListener, PlaybackListener, ImageLoadingListener {
|
Player.EventListener, PlaybackListener, ImageLoadingListener {
|
||||||
|
|
||||||
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
||||||
@NonNull
|
@NonNull
|
||||||
public static final String TAG = "BasePlayer";
|
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
|
@NonNull
|
||||||
public static final String REPEAT_MODE = "repeat_mode";
|
public static final String REPEAT_MODE = "repeat_mode";
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -123,26 +135,43 @@ public abstract class BasePlayer implements
|
||||||
public static final String START_PAUSED = "start_paused";
|
public static final String START_PAUSED = "start_paused";
|
||||||
@NonNull
|
@NonNull
|
||||||
public static final String SELECT_ON_APPEND = "select_on_append";
|
public static final String SELECT_ON_APPEND = "select_on_append";
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Intent
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static final String IS_MUTED = "is_muted";
|
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
|
// 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
|
@NonNull
|
||||||
protected final Context context;
|
protected final Context context;
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -158,39 +187,17 @@ public abstract class BasePlayer implements
|
||||||
@NonNull
|
@NonNull
|
||||||
private final LoadControl loadControl;
|
private final LoadControl loadControl;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Player
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final RenderersFactory renderFactory;
|
private final RenderersFactory renderFactory;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final SerialDisposable progressUpdateReactor;
|
private final SerialDisposable progressUpdateReactor;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final CompositeDisposable databaseUpdateReactor;
|
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 boolean isPrepared = false;
|
||||||
private Disposable stateLoader;
|
private Disposable stateLoader;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
protected int currentState = STATE_PREFLIGHT;
|
||||||
// Thumbnail Loading
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
public BasePlayer(@NonNull final Context context) {
|
public BasePlayer(@NonNull final Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -247,8 +254,7 @@ public abstract class BasePlayer implements
|
||||||
registerBroadcastReceiver();
|
registerBroadcastReceiver();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initListeners() {
|
public void initListeners() { }
|
||||||
}
|
|
||||||
|
|
||||||
public void handleIntent(final Intent intent) {
|
public void handleIntent(final Intent intent) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -324,10 +330,6 @@ public abstract class BasePlayer implements
|
||||||
/*playOnInit=*/!intent.getBooleanExtra(START_PAUSED, false), isMuted);
|
/*playOnInit=*/!intent.getBooleanExtra(START_PAUSED, false), isMuted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Broadcast Receiver
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
protected void initPlayback(@NonNull final PlayQueue queue,
|
protected void initPlayback(@NonNull final PlayQueue queue,
|
||||||
@Player.RepeatMode final int repeatMode,
|
@Player.RepeatMode final int repeatMode,
|
||||||
final float playbackSpeed,
|
final float playbackSpeed,
|
||||||
|
@ -398,9 +400,12 @@ public abstract class BasePlayer implements
|
||||||
|
|
||||||
databaseUpdateReactor.clear();
|
databaseUpdateReactor.clear();
|
||||||
progressUpdateReactor.set(null);
|
progressUpdateReactor.set(null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Thumbnail Loading
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void initThumbnail(final String url) {
|
private void initThumbnail(final String url) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Thumbnail - initThumbnail() called");
|
Log.d(TAG, "Thumbnail - initThumbnail() called");
|
||||||
|
@ -413,10 +418,6 @@ public abstract class BasePlayer implements
|
||||||
.loadImage(url, ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, this);
|
.loadImage(url, ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// States Implementation
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadingStarted(final String imageUri, final View view) {
|
public void onLoadingStarted(final String imageUri, final View view) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -453,6 +454,10 @@ public abstract class BasePlayer implements
|
||||||
currentThumbnail = null;
|
currentThumbnail = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Broadcast Receiver
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add your action in the intentFilter.
|
* Add your action in the intentFilter.
|
||||||
*
|
*
|
||||||
|
@ -488,6 +493,10 @@ public abstract class BasePlayer implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// States Implementation
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public void changeState(final int state) {
|
public void changeState(final int state) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "changeState() called with: state = [" + state + "]");
|
Log.d(TAG, "changeState() called with: state = [" + state + "]");
|
||||||
|
@ -1328,6 +1337,7 @@ public abstract class BasePlayer implements
|
||||||
playQueue.append(autoQueue.getStreams());
|
playQueue.append(autoQueue.getStreams());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Getters and Setters
|
// Getters and Setters
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
|
@ -1181,11 +1181,14 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
private class PlayerGestureListener extends GestureDetector.SimpleOnGestureListener
|
private class PlayerGestureListener extends GestureDetector.SimpleOnGestureListener
|
||||||
implements View.OnTouchListener {
|
implements View.OnTouchListener {
|
||||||
private static final int MOVEMENT_THRESHOLD = 40;
|
private static final int MOVEMENT_THRESHOLD = 40;
|
||||||
|
|
||||||
private final boolean isVolumeGestureEnabled = PlayerHelper
|
private final boolean isVolumeGestureEnabled = PlayerHelper
|
||||||
.isVolumeGestureEnabled(getApplicationContext());
|
.isVolumeGestureEnabled(getApplicationContext());
|
||||||
private final boolean isBrightnessGestureEnabled = PlayerHelper
|
private final boolean isBrightnessGestureEnabled = PlayerHelper
|
||||||
.isBrightnessGestureEnabled(getApplicationContext());
|
.isBrightnessGestureEnabled(getApplicationContext());
|
||||||
|
|
||||||
private final int maxVolume = playerImpl.getAudioReactor().getMaxVolume();
|
private final int maxVolume = playerImpl.getAudioReactor().getMaxVolume();
|
||||||
|
|
||||||
private boolean isMoving;
|
private boolean isMoving;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -54,14 +54,19 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||||
View.OnClickListener, PlaybackParameterDialog.Callback {
|
View.OnClickListener, PlaybackParameterDialog.Callback {
|
||||||
private static final int RECYCLER_ITEM_POPUP_MENU_GROUP_ID = 47;
|
private static final int RECYCLER_ITEM_POPUP_MENU_GROUP_ID = 47;
|
||||||
private static final int SMOOTH_SCROLL_MAXIMUM_DISTANCE = 80;
|
private static final int SMOOTH_SCROLL_MAXIMUM_DISTANCE = 80;
|
||||||
|
|
||||||
protected BasePlayer player;
|
protected BasePlayer player;
|
||||||
|
|
||||||
private boolean serviceBound;
|
private boolean serviceBound;
|
||||||
private ServiceConnection serviceConnection;
|
private ServiceConnection serviceConnection;
|
||||||
|
|
||||||
|
private boolean seeking;
|
||||||
|
private boolean redraw;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Views
|
// Views
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
private boolean seeking;
|
|
||||||
private boolean redraw;
|
|
||||||
private View rootView;
|
private View rootView;
|
||||||
|
|
||||||
private RecyclerView itemsList;
|
private RecyclerView itemsList;
|
||||||
|
|
|
@ -90,51 +90,69 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
Player.EventListener,
|
Player.EventListener,
|
||||||
PopupMenu.OnMenuItemClickListener,
|
PopupMenu.OnMenuItemClickListener,
|
||||||
PopupMenu.OnDismissListener {
|
PopupMenu.OnDismissListener {
|
||||||
|
public final String TAG;
|
||||||
public static final boolean DEBUG = BasePlayer.DEBUG;
|
public static final boolean DEBUG = BasePlayer.DEBUG;
|
||||||
public static final int DEFAULT_CONTROLS_DURATION = 300; // 300 millis
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Player
|
// Player
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
public static final int DEFAULT_CONTROLS_DURATION = 300; // 300 millis
|
||||||
public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000; // 2 Seconds
|
public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000; // 2 Seconds
|
||||||
protected static final int RENDERER_UNAVAILABLE = -1;
|
protected static final int RENDERER_UNAVAILABLE = -1;
|
||||||
public final String TAG;
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final VideoPlaybackResolver resolver;
|
private final VideoPlaybackResolver resolver;
|
||||||
private final Handler controlsVisibilityHandler = new Handler();
|
|
||||||
private final int qualityPopupMenuGroupId = 69;
|
private List<VideoStream> availableStreams;
|
||||||
private final int playbackSpeedPopupMenuGroupId = 79;
|
private int selectedStreamIndex;
|
||||||
|
|
||||||
|
protected boolean wasPlaying = false;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Views
|
// Views
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
private final int captionPopupMenuGroupId = 89;
|
|
||||||
protected boolean wasPlaying = false;
|
|
||||||
boolean isSomePopupMenuVisible = false;
|
|
||||||
private List<VideoStream> availableStreams;
|
|
||||||
private int selectedStreamIndex;
|
|
||||||
private View rootView;
|
private View rootView;
|
||||||
|
|
||||||
private AspectRatioFrameLayout aspectRatioFrameLayout;
|
private AspectRatioFrameLayout aspectRatioFrameLayout;
|
||||||
private SurfaceView surfaceView;
|
private SurfaceView surfaceView;
|
||||||
private View surfaceForeground;
|
private View surfaceForeground;
|
||||||
|
|
||||||
private View loadingPanel;
|
private View loadingPanel;
|
||||||
private ImageView endScreen;
|
private ImageView endScreen;
|
||||||
private ImageView controlAnimationView;
|
private ImageView controlAnimationView;
|
||||||
|
|
||||||
private View controlsRoot;
|
private View controlsRoot;
|
||||||
private TextView currentDisplaySeek;
|
private TextView currentDisplaySeek;
|
||||||
|
|
||||||
private View bottomControlsRoot;
|
private View bottomControlsRoot;
|
||||||
private SeekBar playbackSeekBar;
|
private SeekBar playbackSeekBar;
|
||||||
private TextView playbackCurrentTime;
|
private TextView playbackCurrentTime;
|
||||||
private TextView playbackEndTime;
|
private TextView playbackEndTime;
|
||||||
private TextView playbackLiveSync;
|
private TextView playbackLiveSync;
|
||||||
private TextView playbackSpeedTextView;
|
private TextView playbackSpeedTextView;
|
||||||
|
|
||||||
private View topControlsRoot;
|
private View topControlsRoot;
|
||||||
private TextView qualityTextView;
|
private TextView qualityTextView;
|
||||||
|
|
||||||
private SubtitleView subtitleView;
|
private SubtitleView subtitleView;
|
||||||
|
|
||||||
private TextView resizeView;
|
private TextView resizeView;
|
||||||
private TextView captionTextView;
|
private TextView captionTextView;
|
||||||
|
|
||||||
private ValueAnimator controlViewAnimator;
|
private ValueAnimator controlViewAnimator;
|
||||||
|
private final Handler controlsVisibilityHandler = new Handler();
|
||||||
|
|
||||||
|
boolean isSomePopupMenuVisible = false;
|
||||||
|
|
||||||
|
private final int qualityPopupMenuGroupId = 69;
|
||||||
private PopupMenu qualityPopupMenu;
|
private PopupMenu qualityPopupMenu;
|
||||||
|
|
||||||
|
private final int playbackSpeedPopupMenuGroupId = 79;
|
||||||
private PopupMenu playbackSpeedPopupMenu;
|
private PopupMenu playbackSpeedPopupMenu;
|
||||||
|
|
||||||
|
private final int captionPopupMenuGroupId = 89;
|
||||||
private PopupMenu captionPopupMenu;
|
private PopupMenu captionPopupMenu;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -238,10 +256,6 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// UI Builders
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleIntent(final Intent intent) {
|
public void handleIntent(final Intent intent) {
|
||||||
if (intent == null) {
|
if (intent == null) {
|
||||||
|
@ -255,6 +269,10 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
super.handleIntent(intent);
|
super.handleIntent(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// UI Builders
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public void buildQualityMenu() {
|
public void buildQualityMenu() {
|
||||||
if (qualityPopupMenu == null) {
|
if (qualityPopupMenu == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -354,9 +372,6 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
}
|
}
|
||||||
captionPopupMenu.setOnDismissListener(this);
|
captionPopupMenu.setOnDismissListener(this);
|
||||||
}
|
}
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Playback Listener
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void updateStreamRelatedViews() {
|
private void updateStreamRelatedViews() {
|
||||||
if (getCurrentMetadata() == null) {
|
if (getCurrentMetadata() == null) {
|
||||||
|
@ -413,6 +428,10 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
playbackSpeedTextView.setVisibility(View.VISIBLE);
|
playbackSpeedTextView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Playback Listener
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected abstract VideoPlaybackResolver.QualityResolver getQualityResolver();
|
protected abstract VideoPlaybackResolver.QualityResolver getQualityResolver();
|
||||||
|
|
||||||
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
|
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
|
||||||
|
@ -420,16 +439,16 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
updateStreamRelatedViews();
|
updateStreamRelatedViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// States Implementation
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) {
|
public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) {
|
||||||
return resolver.resolve(info);
|
return resolver.resolve(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// States Implementation
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBlocked() {
|
public void onBlocked() {
|
||||||
super.onBlocked();
|
super.onBlocked();
|
||||||
|
@ -494,10 +513,6 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
showAndAnimateControl(-1, true);
|
showAndAnimateControl(-1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// ExoPlayer Video Listener
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCompleted() {
|
public void onCompleted() {
|
||||||
super.onCompleted();
|
super.onCompleted();
|
||||||
|
@ -510,6 +525,10 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
animateView(surfaceForeground, true, 100);
|
animateView(surfaceForeground, true, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// ExoPlayer Video Listener
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTracksChanged(final TrackGroupArray trackGroups,
|
public void onTracksChanged(final TrackGroupArray trackGroups,
|
||||||
final TrackSelectionArray trackSelections) {
|
final TrackSelectionArray trackSelections) {
|
||||||
|
@ -537,15 +556,15 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
aspectRatioFrameLayout.setAspectRatio(((float) width) / height);
|
aspectRatioFrameLayout.setAspectRatio(((float) width) / height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// ExoPlayer Track Updates
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRenderedFirstFrame() {
|
public void onRenderedFirstFrame() {
|
||||||
animateView(surfaceForeground, false, 100);
|
animateView(surfaceForeground, false, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// ExoPlayer Track Updates
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void onTextTrackUpdate() {
|
private void onTextTrackUpdate() {
|
||||||
final int textRenderer = getRendererIndex(C.TRACK_TYPE_TEXT);
|
final int textRenderer = getRendererIndex(C.TRACK_TYPE_TEXT);
|
||||||
|
|
||||||
|
|
|
@ -20,17 +20,20 @@ import java.io.File;
|
||||||
|
|
||||||
/* package-private */ class CacheFactory implements DataSource.Factory {
|
/* package-private */ class CacheFactory implements DataSource.Factory {
|
||||||
private static final String TAG = "CacheFactory";
|
private static final String TAG = "CacheFactory";
|
||||||
|
|
||||||
private static final String CACHE_FOLDER_NAME = "exoplayer";
|
private static final String CACHE_FOLDER_NAME = "exoplayer";
|
||||||
private static final int CACHE_FLAGS = CacheDataSource.FLAG_BLOCK_ON_CACHE
|
private static final int CACHE_FLAGS = CacheDataSource.FLAG_BLOCK_ON_CACHE
|
||||||
| CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR;
|
| 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
|
// Creating cache on every instance may cause problems with multiple players when
|
||||||
// sources are not ExtractorMediaSource
|
// sources are not ExtractorMediaSource
|
||||||
// see: https://stackoverflow.com/questions/28700391/using-cache-in-exoplayer
|
// see: https://stackoverflow.com/questions/28700391/using-cache-in-exoplayer
|
||||||
// todo: make this a singleton?
|
// todo: make this a singleton?
|
||||||
private static SimpleCache cache;
|
private static SimpleCache cache;
|
||||||
private final DefaultDataSourceFactory dataSourceFactory;
|
|
||||||
private final File cacheDir;
|
|
||||||
private final long maxFileSize;
|
|
||||||
|
|
||||||
CacheFactory(@NonNull final Context context,
|
CacheFactory(@NonNull final Context context,
|
||||||
@NonNull final String userAgent,
|
@NonNull final String userAgent,
|
||||||
|
|
|
@ -23,19 +23,23 @@ import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||||
|
|
||||||
public class PlaybackParameterDialog extends DialogFragment {
|
public class PlaybackParameterDialog extends DialogFragment {
|
||||||
// Minimum allowable range in ExoPlayer
|
// Minimum allowable range in ExoPlayer
|
||||||
public static final double MINIMUM_PLAYBACK_VALUE = 0.10f;
|
private static final double MINIMUM_PLAYBACK_VALUE = 0.10f;
|
||||||
public static final double MAXIMUM_PLAYBACK_VALUE = 3.00f;
|
private static final double MAXIMUM_PLAYBACK_VALUE = 3.00f;
|
||||||
public static final char STEP_UP_SIGN = '+';
|
|
||||||
public static final char STEP_DOWN_SIGN = '-';
|
private static final char STEP_UP_SIGN = '+';
|
||||||
public static final double STEP_ONE_PERCENT_VALUE = 0.01f;
|
private static final char STEP_DOWN_SIGN = '-';
|
||||||
public static final double STEP_FIVE_PERCENT_VALUE = 0.05f;
|
|
||||||
public static final double STEP_TEN_PERCENT_VALUE = 0.10f;
|
private static final double STEP_ONE_PERCENT_VALUE = 0.01f;
|
||||||
public static final double STEP_TWENTY_FIVE_PERCENT_VALUE = 0.25f;
|
private static final double STEP_FIVE_PERCENT_VALUE = 0.05f;
|
||||||
public static final double STEP_ONE_HUNDRED_PERCENT_VALUE = 1.00f;
|
private static final double STEP_TEN_PERCENT_VALUE = 0.10f;
|
||||||
public static final double DEFAULT_TEMPO = 1.00f;
|
private static final double STEP_TWENTY_FIVE_PERCENT_VALUE = 0.25f;
|
||||||
public static final double DEFAULT_PITCH = 1.00f;
|
private static final double STEP_ONE_HUNDRED_PERCENT_VALUE = 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 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
|
@NonNull
|
||||||
private static final String TAG = "PlaybackParameterDialog";
|
private static final String TAG = "PlaybackParameterDialog";
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -49,18 +53,22 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
private static final String PITCH_KEY = "pitch_key";
|
private static final String PITCH_KEY = "pitch_key";
|
||||||
@NonNull
|
@NonNull
|
||||||
private static final String STEP_SIZE_KEY = "step_size_key";
|
private static final String STEP_SIZE_KEY = "step_size_key";
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final SliderStrategy strategy = new SliderStrategy.Quadratic(
|
private final SliderStrategy strategy = new SliderStrategy.Quadratic(
|
||||||
MINIMUM_PLAYBACK_VALUE, MAXIMUM_PLAYBACK_VALUE,
|
MINIMUM_PLAYBACK_VALUE, MAXIMUM_PLAYBACK_VALUE,
|
||||||
/*centerAt=*/1.00f, /*sliderGranularity=*/10000);
|
/*centerAt=*/1.00f, /*sliderGranularity=*/10000);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Callback callback;
|
private Callback callback;
|
||||||
|
|
||||||
private double initialTempo = DEFAULT_TEMPO;
|
private double initialTempo = DEFAULT_TEMPO;
|
||||||
private double initialPitch = DEFAULT_PITCH;
|
private double initialPitch = DEFAULT_PITCH;
|
||||||
private boolean initialSkipSilence = DEFAULT_SKIP_SILENCE;
|
private boolean initialSkipSilence = DEFAULT_SKIP_SILENCE;
|
||||||
private double tempo = DEFAULT_TEMPO;
|
private double tempo = DEFAULT_TEMPO;
|
||||||
private double pitch = DEFAULT_PITCH;
|
private double pitch = DEFAULT_PITCH;
|
||||||
private double stepSize = DEFAULT_STEP;
|
private double stepSize = DEFAULT_STEP;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private SeekBar tempoSlider;
|
private SeekBar tempoSlider;
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -96,25 +104,10 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private static String getStepUpPercentString(final double percent) {
|
|
||||||
return STEP_UP_SIGN + getPercentString(percent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Lifecycle
|
// 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
|
@Override
|
||||||
public void onAttach(final Context context) {
|
public void onAttach(final Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
|
@ -125,10 +118,6 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Dialog
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
assureCorrectAppLanguage(getContext());
|
assureCorrectAppLanguage(getContext());
|
||||||
|
@ -143,10 +132,6 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Control Views
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(final Bundle outState) {
|
public void onSaveInstanceState(final Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
|
@ -158,6 +143,10 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
outState.putDouble(STEP_SIZE_KEY, getCurrentStepSize());
|
outState.putDouble(STEP_SIZE_KEY, getCurrentStepSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Dialog
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
|
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
|
||||||
|
@ -179,6 +168,10 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
return dialogBuilder.create();
|
return dialogBuilder.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Control Views
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void setupControlViews(@NonNull final View rootView) {
|
private void setupControlViews(@NonNull final View rootView) {
|
||||||
setupHookingControl(rootView);
|
setupHookingControl(rootView);
|
||||||
setupSkipSilenceControl(rootView);
|
setupSkipSilenceControl(rootView);
|
||||||
|
@ -273,10 +266,6 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Sliders
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void setupStepSizeSelector(@NonNull final View rootView) {
|
private void setupStepSizeSelector(@NonNull final View rootView) {
|
||||||
TextView stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent);
|
TextView stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent);
|
||||||
TextView stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent);
|
TextView stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent);
|
||||||
|
@ -355,6 +344,10 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Sliders
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private SeekBar.OnSeekBarChangeListener getOnTempoChangedListener() {
|
private SeekBar.OnSeekBarChangeListener getOnTempoChangedListener() {
|
||||||
return new SeekBar.OnSeekBarChangeListener() {
|
return new SeekBar.OnSeekBarChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -430,10 +423,6 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
setPitchSlider(newValue);
|
setPitchSlider(newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Helper
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void setTempoSlider(final double newTempo) {
|
private void setTempoSlider(final double newTempo) {
|
||||||
if (tempoSlider == null) {
|
if (tempoSlider == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -448,6 +437,10 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
pitchSlider.setProgress(strategy.progressOf(newPitch));
|
pitchSlider.setProgress(strategy.progressOf(newPitch));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Helper
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void setCurrentPlaybackParameters() {
|
private void setCurrentPlaybackParameters() {
|
||||||
setPlaybackParameters(getCurrentTempo(), getCurrentPitch(), getCurrentSkipSilence());
|
setPlaybackParameters(getCurrentTempo(), getCurrentPitch(), getCurrentSkipSilence());
|
||||||
}
|
}
|
||||||
|
@ -483,6 +476,21 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
return skipSilenceCheckbox != null && skipSilenceCheckbox.isChecked();
|
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 {
|
public interface Callback {
|
||||||
void onPlaybackParameterChanged(float playbackTempo, float playbackPitch,
|
void onPlaybackParameterChanged(float playbackTempo, float playbackPitch,
|
||||||
boolean playbackSkipSilence);
|
boolean playbackSkipSilence);
|
||||||
|
|
|
@ -58,6 +58,10 @@ public final class PlayerHelper {
|
||||||
|
|
||||||
private PlayerHelper() { }
|
private PlayerHelper() { }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Exposed helpers
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public static String getTimeString(final int milliSeconds) {
|
public static String getTimeString(final int milliSeconds) {
|
||||||
int seconds = (milliSeconds % 60000) / 1000;
|
int seconds = (milliSeconds % 60000) / 1000;
|
||||||
int minutes = (milliSeconds % 3600000) / 60000;
|
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("%d:%02d:%02d", hours, minutes, seconds).toString()
|
||||||
: STRING_FORMATTER.format("%02d:%02d", minutes, seconds).toString();
|
: STRING_FORMATTER.format("%02d:%02d", minutes, seconds).toString();
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Exposed helpers
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public static String formatSpeed(final double speed) {
|
public static String formatSpeed(final double speed) {
|
||||||
return SPEED_FORMATTER.format(speed);
|
return SPEED_FORMATTER.format(speed);
|
||||||
|
@ -177,14 +178,14 @@ public final class PlayerHelper {
|
||||||
? null : getAutoQueuedSinglePlayQueue(autoQueueItems.get(0));
|
? null : getAutoQueuedSinglePlayQueue(autoQueueItems.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) {
|
|
||||||
return isResumeAfterAudioFocusGain(context, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Settings Resolution
|
// Settings Resolution
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) {
|
||||||
|
return isResumeAfterAudioFocusGain(context, false);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isVolumeGestureEnabled(@NonNull final Context context) {
|
public static boolean isVolumeGestureEnabled(@NonNull final Context context) {
|
||||||
return isVolumeGestureEnabled(context, true);
|
return isVolumeGestureEnabled(context, true);
|
||||||
}
|
}
|
||||||
|
@ -322,15 +323,15 @@ public final class PlayerHelper {
|
||||||
setScreenBrightness(context, setScreenBrightness, System.currentTimeMillis());
|
setScreenBrightness(context, setScreenBrightness, System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Private helpers
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static SharedPreferences getPreferences(@NonNull final Context context) {
|
private static SharedPreferences getPreferences(@NonNull final Context context) {
|
||||||
return PreferenceManager.getDefaultSharedPreferences(context);
|
return PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private helpers
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private static boolean isResumeAfterAudioFocusGain(@NonNull final Context context,
|
private static boolean isResumeAfterAudioFocusGain(@NonNull final Context context,
|
||||||
final boolean b) {
|
final boolean b) {
|
||||||
return getPreferences(context)
|
return getPreferences(context)
|
||||||
|
|
|
@ -44,16 +44,21 @@ import static org.schabi.newpipe.player.mediasource.FailedMediaSource.StreamInfo
|
||||||
import static org.schabi.newpipe.player.playqueue.PlayQueue.DEBUG;
|
import static org.schabi.newpipe.player.playqueue.PlayQueue.DEBUG;
|
||||||
|
|
||||||
public class MediaSourceManager {
|
public class MediaSourceManager {
|
||||||
|
@NonNull
|
||||||
|
private final String TAG = "MediaSourceManager@" + hashCode();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines how many streams before and after the current stream should be loaded.
|
* Determines how many streams before and after the current stream should be loaded.
|
||||||
* The default value (1) ensures seamless playback under typical network settings.
|
* 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
|
* The streams after the current will be loaded into the playlist timeline while the
|
||||||
* streams before will only be cached for future usage.
|
* streams before will only be cached for future usage.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @see #onMediaSourceReceived(PlayQueueItem, ManagedMediaSource)
|
* @see #onMediaSourceReceived(PlayQueueItem, ManagedMediaSource)
|
||||||
*/
|
*/
|
||||||
private static final int WINDOW_SIZE = 1;
|
private static final int WINDOW_SIZE = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines the maximum number of disposables allowed in the {@link #loaderReactor}.
|
* Determines the maximum number of disposables allowed in the {@link #loaderReactor}.
|
||||||
* Once exceeded, new calls to {@link #loadImmediate()} will evict all disposables in the
|
* Once exceeded, new calls to {@link #loadImmediate()} will evict all disposables in the
|
||||||
|
@ -63,12 +68,12 @@ public class MediaSourceManager {
|
||||||
* @see #maybeLoadItem(PlayQueueItem)
|
* @see #maybeLoadItem(PlayQueueItem)
|
||||||
*/
|
*/
|
||||||
private static final int MAXIMUM_LOADER_SIZE = WINDOW_SIZE * 2 + 1;
|
private static final int MAXIMUM_LOADER_SIZE = WINDOW_SIZE * 2 + 1;
|
||||||
@NonNull
|
|
||||||
private final String TAG = "MediaSourceManager@" + hashCode();
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final PlaybackListener playbackListener;
|
private final PlaybackListener playbackListener;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final PlayQueue playQueue;
|
private final PlayQueue playQueue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines the gap time between the playback position and the playback duration which
|
* Determines the gap time between the playback position and the playback duration which
|
||||||
* the {@link #getEdgeIntervalSignal()} begins to request loading.
|
* the {@link #getEdgeIntervalSignal()} begins to request loading.
|
||||||
|
@ -76,35 +81,45 @@ public class MediaSourceManager {
|
||||||
* @see #progressUpdateIntervalMillis
|
* @see #progressUpdateIntervalMillis
|
||||||
*/
|
*/
|
||||||
private final long playbackNearEndGapMillis;
|
private final long playbackNearEndGapMillis;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines the interval which the {@link #getEdgeIntervalSignal()} waits for between
|
* Determines the interval which the {@link #getEdgeIntervalSignal()} waits for between
|
||||||
* each request for loading, once {@link #playbackNearEndGapMillis} has reached.
|
* each request for loading, once {@link #playbackNearEndGapMillis} has reached.
|
||||||
*/
|
*/
|
||||||
private final long progressUpdateIntervalMillis;
|
private final long progressUpdateIntervalMillis;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Observable<Long> nearEndIntervalSignal;
|
private final Observable<Long> nearEndIntervalSignal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process only the last load order when receiving a stream of load orders (lessens I/O).
|
* 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.
|
* The higher it is, the less loading occurs during rapid noncritical timeline changes.
|
||||||
* <br><br>
|
* </p>
|
||||||
|
* <p>
|
||||||
* Not recommended to go below 100ms.
|
* Not recommended to go below 100ms.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @see #loadDebounced()
|
* @see #loadDebounced()
|
||||||
*/
|
*/
|
||||||
private final long loadDebounceMillis;
|
private final long loadDebounceMillis;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Disposable debouncedLoader;
|
private final Disposable debouncedLoader;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final PublishSubject<Long> debouncedSignal;
|
private final PublishSubject<Long> debouncedSignal;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Subscription playQueueReactor;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final CompositeDisposable loaderReactor;
|
private final CompositeDisposable loaderReactor;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Set<PlayQueueItem> loadingItems;
|
private final Set<PlayQueueItem> loadingItems;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final AtomicBoolean isBlocked;
|
private final AtomicBoolean isBlocked;
|
||||||
@NonNull
|
|
||||||
private Subscription playQueueReactor;
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private ManagedMediaSourcePlaylist playlist;
|
private ManagedMediaSourcePlaylist playlist;
|
||||||
|
|
||||||
|
@ -160,42 +175,6 @@ public class MediaSourceManager {
|
||||||
// Exposed Methods
|
// 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.
|
* Dispose the manager and releases all message buses and loaders.
|
||||||
*/
|
*/
|
||||||
|
@ -211,6 +190,10 @@ public class MediaSourceManager {
|
||||||
loaderReactor.dispose();
|
loaderReactor.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Event Reactor
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private Subscriber<PlayQueueEvent> getReactor() {
|
private Subscriber<PlayQueueEvent> getReactor() {
|
||||||
return new Subscriber<PlayQueueEvent>() {
|
return new Subscriber<PlayQueueEvent>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -233,10 +216,6 @@ public class MediaSourceManager {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Playback Locking
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void onPlayQueueChanged(final PlayQueueEvent event) {
|
private void onPlayQueueChanged(final PlayQueueEvent event) {
|
||||||
if (playQueue.isEmpty() && playQueue.isComplete()) {
|
if (playQueue.isEmpty() && playQueue.isComplete()) {
|
||||||
playbackListener.onPlaybackShutdown();
|
playbackListener.onPlaybackShutdown();
|
||||||
|
@ -298,6 +277,10 @@ public class MediaSourceManager {
|
||||||
playQueueReactor.request(1);
|
playQueueReactor.request(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Playback Locking
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private boolean isPlayQueueReady() {
|
private boolean isPlayQueueReady() {
|
||||||
final boolean isWindowLoaded = playQueue.size() - playQueue.getIndex() > WINDOW_SIZE;
|
final boolean isWindowLoaded = playQueue.size() - playQueue.getIndex() > WINDOW_SIZE;
|
||||||
return playQueue.isComplete() || isWindowLoaded;
|
return playQueue.isComplete() || isWindowLoaded;
|
||||||
|
@ -332,10 +315,6 @@ public class MediaSourceManager {
|
||||||
isBlocked.set(true);
|
isBlocked.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Metadata Synchronization
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void maybeUnblock() {
|
private void maybeUnblock() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "maybeUnblock() called.");
|
Log.d(TAG, "maybeUnblock() called.");
|
||||||
|
@ -347,6 +326,10 @@ public class MediaSourceManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Metadata Synchronization
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void maybeSync() {
|
private void maybeSync() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "maybeSync() called.");
|
Log.d(TAG, "maybeSync() called.");
|
||||||
|
@ -360,10 +343,6 @@ public class MediaSourceManager {
|
||||||
playbackListener.onPlaybackSynchronize(currentItem);
|
playbackListener.onPlaybackSynchronize(currentItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// MediaSource Loading
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private synchronized void maybeSynchronizePlayer() {
|
private synchronized void maybeSynchronizePlayer() {
|
||||||
if (isPlayQueueReady() && isPlaybackReady()) {
|
if (isPlayQueueReady() && isPlaybackReady()) {
|
||||||
maybeUnblock();
|
maybeUnblock();
|
||||||
|
@ -371,6 +350,10 @@ public class MediaSourceManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// MediaSource Loading
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private Observable<Long> getEdgeIntervalSignal() {
|
private Observable<Long> getEdgeIntervalSignal() {
|
||||||
return Observable.interval(progressUpdateIntervalMillis, TimeUnit.MILLISECONDS)
|
return Observable.interval(progressUpdateIntervalMillis, TimeUnit.MILLISECONDS)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
@ -523,9 +506,6 @@ public class MediaSourceManager {
|
||||||
}
|
}
|
||||||
playlist.invalidate(currentIndex, removeMediaSourceHandler, this::loadImmediate);
|
playlist.invalidate(currentIndex, removeMediaSourceHandler, this::loadImmediate);
|
||||||
}
|
}
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// MediaSource Playlist Helpers
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void maybeClearLoaders() {
|
private void maybeClearLoaders() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -538,6 +518,10 @@ public class MediaSourceManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// MediaSource Playlist Helpers
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void resetSources() {
|
private void resetSources() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "resetSources() called.");
|
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 {
|
private static class ItemsToLoad {
|
||||||
@NonNull
|
@NonNull
|
||||||
private final PlayQueueItem center;
|
private final PlayQueueItem center;
|
||||||
|
|
|
@ -16,10 +16,11 @@ import io.reactivex.annotations.NonNull;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
|
|
||||||
abstract class AbstractInfoPlayQueue<T extends ListInfo, U extends InfoItem> extends PlayQueue {
|
abstract class AbstractInfoPlayQueue<T extends ListInfo, U extends InfoItem> extends PlayQueue {
|
||||||
final int serviceId;
|
|
||||||
final String baseUrl;
|
|
||||||
boolean isInitial;
|
boolean isInitial;
|
||||||
private boolean isComplete;
|
private boolean isComplete;
|
||||||
|
|
||||||
|
final int serviceId;
|
||||||
|
final String baseUrl;
|
||||||
String nextUrl;
|
String nextUrl;
|
||||||
|
|
||||||
private transient Disposable fetchReactor;
|
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());
|
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();
|
protected abstract String getTag();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -134,4 +125,14 @@ abstract class AbstractInfoPlayQueue<T extends ListInfo, U extends InfoItem> ext
|
||||||
}
|
}
|
||||||
fetchReactor = null;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,17 +36,22 @@ import io.reactivex.subjects.BehaviorSubject;
|
||||||
* <p>
|
* <p>
|
||||||
* This class contains basic manipulation of a playlist while also functions as a
|
* 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.
|
* message bus, providing all listeners with new updates to the play queue.
|
||||||
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* This class can be serialized for passing intents, but in order to start the
|
* This class can be serialized for passing intents, but in order to start the
|
||||||
* message bus, it must be initialized.
|
* message bus, it must be initialized.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
public abstract class PlayQueue implements Serializable {
|
public abstract class PlayQueue implements Serializable {
|
||||||
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
|
||||||
private final String TAG = "PlayQueue@" + Integer.toHexString(hashCode());
|
private final String TAG = "PlayQueue@" + Integer.toHexString(hashCode());
|
||||||
@NonNull
|
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
||||||
private final AtomicInteger queueIndex;
|
|
||||||
private ArrayList<PlayQueueItem> backup;
|
private ArrayList<PlayQueueItem> backup;
|
||||||
private ArrayList<PlayQueueItem> streams;
|
private ArrayList<PlayQueueItem> streams;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final AtomicInteger queueIndex;
|
||||||
|
|
||||||
private transient BehaviorSubject<PlayQueueEvent> eventBroadcast;
|
private transient BehaviorSubject<PlayQueueEvent> eventBroadcast;
|
||||||
private transient Flowable<PlayQueueEvent> broadcastReceiver;
|
private transient Flowable<PlayQueueEvent> broadcastReceiver;
|
||||||
private transient Subscription reportingReactor;
|
private transient Subscription reportingReactor;
|
||||||
|
|
|
@ -28,19 +28,23 @@ import io.reactivex.disposables.Disposable;
|
||||||
* <p>
|
* <p>
|
||||||
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||||
* InfoListAdapter.java is part of NewPipe.
|
* InfoListAdapter.java is part of NewPipe.
|
||||||
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* NewPipe is free software: you can redistribute it and/or modify
|
* NewPipe is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* NewPipe is distributed in the hope that it will be useful,
|
* NewPipe is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class PlayQueueAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
public class PlayQueueAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
|
|
|
@ -32,6 +32,7 @@ public class VideoPlaybackResolver implements PlaybackResolver {
|
||||||
private final PlayerDataSource dataSource;
|
private final PlayerDataSource dataSource;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final QualityResolver qualityResolver;
|
private final QualityResolver qualityResolver;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private String playbackQuality;
|
private String playbackQuality;
|
||||||
|
|
||||||
|
|
|
@ -181,25 +181,6 @@ public class ErrorActivity extends AppCompatActivity {
|
||||||
return out;
|
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
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
assureCorrectAppLanguage(this);
|
assureCorrectAppLanguage(this);
|
||||||
|
@ -315,6 +296,25 @@ public class ErrorActivity extends AppCompatActivity {
|
||||||
return text.toString();
|
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() {
|
private void goToReturnActivity() {
|
||||||
Class<? extends Activity> checkedReturnActivity = getReturnActivity(returnActivity);
|
Class<? extends Activity> checkedReturnActivity = getReturnActivity(returnActivity);
|
||||||
if (checkedReturnActivity == null) {
|
if (checkedReturnActivity == null) {
|
||||||
|
|
|
@ -54,17 +54,20 @@ import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
public class PeertubeInstanceListFragment extends Fragment {
|
public class PeertubeInstanceListFragment extends Fragment {
|
||||||
private static final int MENU_ITEM_RESTORE_ID = 123456;
|
private static final int MENU_ITEM_RESTORE_ID = 123456;
|
||||||
public InstanceListAdapter instanceListAdapter;
|
|
||||||
private List<PeertubeInstance> instanceList = new ArrayList<>();
|
private List<PeertubeInstance> instanceList = new ArrayList<>();
|
||||||
private PeertubeInstance selectedInstance;
|
private PeertubeInstance selectedInstance;
|
||||||
private String savedInstanceListKey;
|
private String savedInstanceListKey;
|
||||||
|
private InstanceListAdapter instanceListAdapter;
|
||||||
|
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
private SharedPreferences sharedPreferences;
|
private SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
|
private CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
private CompositeDisposable disposables = new CompositeDisposable();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
|
@ -122,9 +125,6 @@ public class PeertubeInstanceListFragment extends Fragment {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
saveChanges();
|
saveChanges();
|
||||||
}
|
}
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Menu
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
|
@ -135,6 +135,10 @@ public class PeertubeInstanceListFragment extends Fragment {
|
||||||
disposables = null;
|
disposables = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Menu
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
@ -284,10 +288,6 @@ public class PeertubeInstanceListFragment extends Fragment {
|
||||||
instanceListAdapter.notifyDataSetChanged();
|
instanceListAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// List Handling
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
|
private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
|
||||||
return new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
|
return new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
|
||||||
ItemTouchHelper.START | ItemTouchHelper.END) {
|
ItemTouchHelper.START | ItemTouchHelper.END) {
|
||||||
|
@ -348,6 +348,10 @@ public class PeertubeInstanceListFragment extends Fragment {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// List Handling
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private class InstanceListAdapter
|
private class InstanceListAdapter
|
||||||
extends RecyclerView.Adapter<InstanceListAdapter.TabViewHolder> {
|
extends RecyclerView.Adapter<InstanceListAdapter.TabViewHolder> {
|
||||||
private final LayoutInflater inflater;
|
private final LayoutInflater inflater;
|
||||||
|
|
|
@ -57,18 +57,18 @@ public class SelectChannelFragment extends DialogFragment {
|
||||||
/**
|
/**
|
||||||
* This contains the base display options for images.
|
* 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();
|
= new DisplayImageOptions.Builder().cacheInMemory(true).build();
|
||||||
private final ImageLoader imageLoader = ImageLoader.getInstance();
|
|
||||||
OnSelectedLisener onSelectedLisener = null;
|
|
||||||
OnCancelListener onCancelListener = null;
|
|
||||||
private ProgressBar progressBar;
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
private final ImageLoader imageLoader = ImageLoader.getInstance();
|
||||||
// Interfaces
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
private OnSelectedLisener onSelectedLisener = null;
|
||||||
|
private OnCancelListener onCancelListener = null;
|
||||||
|
|
||||||
|
private ProgressBar progressBar;
|
||||||
private TextView emptyView;
|
private TextView emptyView;
|
||||||
private RecyclerView recyclerView;
|
private RecyclerView recyclerView;
|
||||||
|
|
||||||
private List<SubscriptionEntity> subscriptions = new Vector<>();
|
private List<SubscriptionEntity> subscriptions = new Vector<>();
|
||||||
|
|
||||||
public void setOnSelectedLisener(final OnSelectedLisener listener) {
|
public void setOnSelectedLisener(final OnSelectedLisener listener) {
|
||||||
|
@ -79,6 +79,10 @@ public class SelectChannelFragment extends DialogFragment {
|
||||||
onCancelListener = listener;
|
onCancelListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Init
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
|
public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
|
||||||
final Bundle savedInstanceState) {
|
final Bundle savedInstanceState) {
|
||||||
|
@ -105,7 +109,7 @@ public class SelectChannelFragment extends DialogFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Init
|
// Handle actions
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -116,11 +120,6 @@ public class SelectChannelFragment extends DialogFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Handle actions
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void clickedItem(final int position) {
|
private void clickedItem(final int position) {
|
||||||
if (onSelectedLisener != null) {
|
if (onSelectedLisener != null) {
|
||||||
SubscriptionEntity entry = subscriptions.get(position);
|
SubscriptionEntity entry = subscriptions.get(position);
|
||||||
|
@ -130,6 +129,10 @@ public class SelectChannelFragment extends DialogFragment {
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Item handling
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void displayChannels(final List<SubscriptionEntity> newSubscriptions) {
|
private void displayChannels(final List<SubscriptionEntity> newSubscriptions) {
|
||||||
this.subscriptions = newSubscriptions;
|
this.subscriptions = newSubscriptions;
|
||||||
progressBar.setVisibility(View.GONE);
|
progressBar.setVisibility(View.GONE);
|
||||||
|
@ -141,10 +144,6 @@ public class SelectChannelFragment extends DialogFragment {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Item handling
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private Observer<List<SubscriptionEntity>> getSubscriptionObserver() {
|
private Observer<List<SubscriptionEntity>> getSubscriptionObserver() {
|
||||||
return new Observer<List<SubscriptionEntity>>() {
|
return new Observer<List<SubscriptionEntity>>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -165,29 +164,28 @@ public class SelectChannelFragment extends DialogFragment {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Error
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected void onError(final Throwable e) {
|
protected void onError(final Throwable e) {
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
ErrorActivity.reportError(activity, e, activity.getClass(), null, ErrorActivity.ErrorInfo
|
ErrorActivity.reportError(activity, e, activity.getClass(), null, ErrorActivity.ErrorInfo
|
||||||
.make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash));
|
.make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Interfaces
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public interface OnSelectedLisener {
|
public interface OnSelectedLisener {
|
||||||
void onChannelSelected(int serviceId, String url, String name);
|
void onChannelSelected(int serviceId, String url, String name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Error
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
public interface OnCancelListener {
|
public interface OnCancelListener {
|
||||||
void onCancel();
|
void onCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// ImageLoaderOptions
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private class SelectChannelAdapter
|
private class SelectChannelAdapter
|
||||||
extends RecyclerView.Adapter<SelectChannelAdapter.SelectChannelItemHolder> {
|
extends RecyclerView.Adapter<SelectChannelAdapter.SelectChannelItemHolder> {
|
||||||
@Override
|
@Override
|
||||||
|
@ -219,8 +217,8 @@ public class SelectChannelFragment extends DialogFragment {
|
||||||
|
|
||||||
public class SelectChannelItemHolder extends RecyclerView.ViewHolder {
|
public class SelectChannelItemHolder extends RecyclerView.ViewHolder {
|
||||||
public final View view;
|
public final View view;
|
||||||
public final CircleImageView thumbnailView;
|
final CircleImageView thumbnailView;
|
||||||
public final TextView titleView;
|
final TextView titleView;
|
||||||
SelectChannelItemHolder(final View v) {
|
SelectChannelItemHolder(final View v) {
|
||||||
super(v);
|
super(v);
|
||||||
this.view = v;
|
this.view = v;
|
||||||
|
|
|
@ -50,9 +50,6 @@ public class SelectKioskFragment extends DialogFragment {
|
||||||
private RecyclerView recyclerView = null;
|
private RecyclerView recyclerView = null;
|
||||||
private SelectKioskAdapter selectKioskAdapter = null;
|
private SelectKioskAdapter selectKioskAdapter = null;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Interfaces
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
private OnSelectedLisener onSelectedLisener = null;
|
private OnSelectedLisener onSelectedLisener = null;
|
||||||
private OnCancelListener onCancelListener = null;
|
private OnCancelListener onCancelListener = null;
|
||||||
|
|
||||||
|
@ -80,6 +77,10 @@ public class SelectKioskFragment extends DialogFragment {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Handle actions
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancel(final DialogInterface dialogInterface) {
|
public void onCancel(final DialogInterface dialogInterface) {
|
||||||
super.onCancel(dialogInterface);
|
super.onCancel(dialogInterface);
|
||||||
|
@ -96,7 +97,7 @@ public class SelectKioskFragment extends DialogFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Handle actions
|
// Error
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected void onError(final Throwable e) {
|
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));
|
.make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Interfaces
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public interface OnSelectedLisener {
|
public interface OnSelectedLisener {
|
||||||
void onKioskSelected(int serviceId, String kioskId, String kioskName);
|
void onKioskSelected(int serviceId, String kioskId, String kioskName);
|
||||||
}
|
}
|
||||||
|
@ -113,10 +118,6 @@ public class SelectKioskFragment extends DialogFragment {
|
||||||
void onCancel();
|
void onCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Error
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private class SelectKioskAdapter
|
private class SelectKioskAdapter
|
||||||
extends RecyclerView.Adapter<SelectKioskAdapter.SelectKioskItemHolder> {
|
extends RecyclerView.Adapter<SelectKioskAdapter.SelectKioskItemHolder> {
|
||||||
private final List<Entry> kioskList = new Vector<>();
|
private final List<Entry> kioskList = new Vector<>();
|
||||||
|
|
|
@ -45,10 +45,11 @@ import static org.schabi.newpipe.settings.tabs.Tab.typeFrom;
|
||||||
|
|
||||||
public class ChooseTabsFragment extends Fragment {
|
public class ChooseTabsFragment extends Fragment {
|
||||||
private static final int MENU_ITEM_RESTORE_ID = 123456;
|
private static final int MENU_ITEM_RESTORE_ID = 123456;
|
||||||
private ChooseTabsFragment.SelectedTabsAdapter selectedTabsAdapter;
|
|
||||||
private TabsManager tabsManager;
|
private TabsManager tabsManager;
|
||||||
|
|
||||||
private List<Tab> tabList = new ArrayList<>();
|
private List<Tab> tabList = new ArrayList<>();
|
||||||
|
private ChooseTabsFragment.SelectedTabsAdapter selectedTabsAdapter;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
|
@ -93,16 +94,16 @@ public class ChooseTabsFragment extends Fragment {
|
||||||
updateTitle();
|
updateTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Menu
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
saveChanges();
|
saveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Menu
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||||
super.onCreateOptionsMenu(menu, 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<>();
|
final ArrayList<ChooseTabListItem> returnList = new ArrayList<>();
|
||||||
|
|
||||||
for (Tab.Type type : Tab.Type.values()) {
|
for (Tab.Type type : Tab.Type.values()) {
|
||||||
|
|
|
@ -39,6 +39,10 @@ public abstract class Tab {
|
||||||
readDataFromJson(jsonObject);
|
readDataFromJson(jsonObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tab Handling
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Tab from(@NonNull final JsonObject jsonObject) {
|
public static Tab from(@NonNull final JsonObject jsonObject) {
|
||||||
final int tabId = jsonObject.getInt(Tab.JSON_TAB_ID_KEY, -1);
|
final int tabId = jsonObject.getInt(Tab.JSON_TAB_ID_KEY, -1);
|
||||||
|
@ -85,10 +89,6 @@ public abstract class Tab {
|
||||||
return type.getTab();
|
return type.getTab();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// JSON Handling
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
public abstract int getTabId();
|
public abstract int getTabId();
|
||||||
|
|
||||||
public abstract String getTabName(Context context);
|
public abstract String getTabName(Context context);
|
||||||
|
@ -104,10 +104,6 @@ public abstract class Tab {
|
||||||
*/
|
*/
|
||||||
public abstract Fragment getFragment(Context context) throws ExtractionException;
|
public abstract Fragment getFragment(Context context) throws ExtractionException;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Tab Handling
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object obj) {
|
public boolean equals(final Object obj) {
|
||||||
if (obj == this) {
|
if (obj == this) {
|
||||||
|
@ -118,6 +114,10 @@ public abstract class Tab {
|
||||||
&& ((Tab) obj).getTabId() == this.getTabId();
|
&& ((Tab) obj).getTabId() == this.getTabId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// JSON Handling
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public void writeJsonOn(final JsonSink jsonSink) {
|
public void writeJsonOn(final JsonSink jsonSink) {
|
||||||
jsonSink.object();
|
jsonSink.object();
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,6 @@ public final class TabsManager {
|
||||||
sharedPreferences.edit().putString(savedTabsKey, jsonToSave).apply();
|
sharedPreferences.edit().putString(savedTabsKey, jsonToSave).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Listener
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
public void resetTabs() {
|
public void resetTabs() {
|
||||||
sharedPreferences.edit().remove(savedTabsKey).apply();
|
sharedPreferences.edit().remove(savedTabsKey).apply();
|
||||||
}
|
}
|
||||||
|
@ -53,6 +49,10 @@ public final class TabsManager {
|
||||||
return TabsJsonHelper.getDefaultTabs();
|
return TabsJsonHelper.getDefaultTabs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Listener
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public void setSavedTabsListener(final SavedTabsChangeListener listener) {
|
public void setSavedTabsListener(final SavedTabsChangeListener listener) {
|
||||||
if (preferenceChangeListener != null) {
|
if (preferenceChangeListener != null) {
|
||||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
|
sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
|
||||||
|
@ -83,12 +83,4 @@ public final class TabsManager {
|
||||||
public interface SavedTabsChangeListener {
|
public interface SavedTabsChangeListener {
|
||||||
void onTabsChanged();
|
void onTabsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,15 +32,17 @@ import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public final class InfoCache {
|
public final class InfoCache {
|
||||||
|
private final String TAG = getClass().getSimpleName();
|
||||||
private static final boolean DEBUG = MainActivity.DEBUG;
|
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
|
||||||
private static final InfoCache INSTANCE = new InfoCache();
|
private static final InfoCache INSTANCE = new InfoCache();
|
||||||
private static final int MAX_ITEMS_ON_CACHE = 60;
|
private static final int MAX_ITEMS_ON_CACHE = 60;
|
||||||
/**
|
/**
|
||||||
* Trim the cache to this size.
|
* Trim the cache to this size.
|
||||||
*/
|
*/
|
||||||
private static final int TRIM_CACHE_TO = 30;
|
private static final int TRIM_CACHE_TO = 30;
|
||||||
|
|
||||||
private static final LruCache<String, CacheData> LRU_CACHE = new LruCache<>(MAX_ITEMS_ON_CACHE);
|
private static final LruCache<String, CacheData> LRU_CACHE = new LruCache<>(MAX_ITEMS_ON_CACHE);
|
||||||
private final String TAG = getClass().getSimpleName();
|
|
||||||
|
|
||||||
private InfoCache() {
|
private InfoCache() {
|
||||||
// no instance
|
// no instance
|
||||||
|
|
|
@ -47,26 +47,26 @@ import static org.schabi.newpipe.MainActivity.DEBUG;
|
||||||
* A view that can be fully collapsed and expanded.
|
* A view that can be fully collapsed and expanded.
|
||||||
*/
|
*/
|
||||||
public class CollapsibleView extends LinearLayout {
|
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 COLLAPSED = 0;
|
||||||
public static final int EXPANDED = 1;
|
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
|
@State
|
||||||
@ViewMode
|
@ViewMode
|
||||||
int currentState = COLLAPSED;
|
int currentState = COLLAPSED;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Collapse/expand logic
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
private boolean readyToChangeState;
|
private boolean readyToChangeState;
|
||||||
|
|
||||||
private int targetHeight = -1;
|
private int targetHeight = -1;
|
||||||
private ValueAnimator currentAnimator;
|
private ValueAnimator currentAnimator;
|
||||||
|
private final List<StateListener> listeners = new ArrayList<>();
|
||||||
|
|
||||||
public CollapsibleView(final Context context) {
|
public CollapsibleView(final Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CollapsibleView(final Context context, @Nullable final AttributeSet attrs) {
|
public CollapsibleView(final Context context, @Nullable final AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
}
|
}
|
||||||
|
@ -75,12 +75,17 @@ public class CollapsibleView extends LinearLayout {
|
||||||
final int defStyleAttr) {
|
final int defStyleAttr) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||||
public CollapsibleView(final Context context, final AttributeSet attrs, final int defStyleAttr,
|
public CollapsibleView(final Context context, final AttributeSet attrs, final int defStyleAttr,
|
||||||
final int defStyleRes) {
|
final int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, 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
|
* 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).
|
* some child changes (e.g. add new views, change text).
|
||||||
|
@ -198,6 +203,10 @@ public class CollapsibleView extends LinearLayout {
|
||||||
listeners.remove(listener);
|
listeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// State Saving
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Parcelable onSaveInstanceState() {
|
public Parcelable onSaveInstanceState() {
|
||||||
|
@ -212,7 +221,7 @@ public class CollapsibleView extends LinearLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// State Saving
|
// Internal
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public String getDebugLogString(final String description) {
|
public String getDebugLogString(final String description) {
|
||||||
|
@ -226,12 +235,7 @@ public class CollapsibleView extends LinearLayout {
|
||||||
|
|
||||||
@Retention(SOURCE)
|
@Retention(SOURCE)
|
||||||
@IntDef({COLLAPSED, EXPANDED})
|
@IntDef({COLLAPSED, EXPANDED})
|
||||||
public @interface ViewMode {
|
public @interface ViewMode { }
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Internal
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple interface used for listening state changes of the {@link CollapsibleView}.
|
* Simple interface used for listening state changes of the {@link CollapsibleView}.
|
||||||
|
|
Loading…
Reference in New Issue