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