From 63bcc04effdd6946a738c70606832a97e429b7a6 Mon Sep 17 00:00:00 2001 From: wb9688 Date: Thu, 2 Apr 2020 13:51:10 +0200 Subject: [PATCH] Move things back to its original place --- .../newpipe/CheckForNewAppVersionTask.java | 2 +- .../newpipe/download/DownloadDialog.java | 22 +-- .../fragments/detail/VideoDetailFragment.java | 118 +++++++++------- .../fragments/list/BaseListFragment.java | 18 +-- .../list/channel/ChannelFragment.java | 27 ++-- .../list/playlist/PlaylistFragment.java | 2 +- .../fragments/list/search/SearchFragment.java | 68 +++++---- .../list/videos/RelatedVideosFragment.java | 21 +-- .../local/bookmark/BookmarkFragment.java | 41 +++--- .../history/StatisticsPlaylistFragment.java | 49 +++---- .../local/playlist/LocalPlaylistFragment.java | 4 +- .../SubscriptionsImportFragment.java | 10 +- .../services/BaseImportExportService.java | 19 ++- .../services/SubscriptionsImportService.java | 11 +- .../org/schabi/newpipe/player/BasePlayer.java | 108 +++++++------- .../newpipe/player/MainVideoPlayer.java | 3 + .../newpipe/player/ServicePlayerActivity.java | 9 +- .../schabi/newpipe/player/VideoPlayer.java | 77 ++++++---- .../newpipe/player/helper/CacheFactory.java | 9 +- .../helper/PlaybackParameterDialog.java | 96 +++++++------ .../newpipe/player/helper/PlayerHelper.java | 23 +-- .../player/playback/MediaSourceManager.java | 133 ++++++++++-------- .../playqueue/AbstractInfoPlayQueue.java | 25 ++-- .../newpipe/player/playqueue/PlayQueue.java | 11 +- .../player/playqueue/PlayQueueAdapter.java | 4 + .../resolver/VideoPlaybackResolver.java | 1 + .../schabi/newpipe/report/ErrorActivity.java | 38 ++--- .../PeertubeInstanceListFragment.java | 22 +-- .../settings/SelectChannelFragment.java | 56 ++++---- .../newpipe/settings/SelectKioskFragment.java | 19 +-- .../settings/tabs/ChooseTabsFragment.java | 13 +- .../org/schabi/newpipe/settings/tabs/Tab.java | 16 +-- .../newpipe/settings/tabs/TabsManager.java | 16 +-- .../org/schabi/newpipe/util/InfoCache.java | 6 +- .../schabi/newpipe/views/CollapsibleView.java | 32 +++-- 35 files changed, 630 insertions(+), 499 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersionTask.java b/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersionTask.java index 12797bd8e..1f2808bed 100644 --- a/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersionTask.java +++ b/app/src/main/java/org/schabi/newpipe/CheckForNewAppVersionTask.java @@ -204,7 +204,7 @@ public class CheckForNewAppVersionTask extends AsyncTask { * * @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, diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java index bdd358eaf..ac6ac0717 100644 --- a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java @@ -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 wrappedAudioStreams = StreamSizeWrapper.empty(); + StreamSizeWrapper wrappedAudioStreams = StreamSizeWrapper.empty(); @State - protected StreamSizeWrapper wrappedVideoStreams = StreamSizeWrapper.empty(); + StreamSizeWrapper wrappedVideoStreams = StreamSizeWrapper.empty(); @State - protected StreamSizeWrapper wrappedSubtitleStreams = StreamSizeWrapper.empty(); + StreamSizeWrapper 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 audioStreamsAdapter; private StreamItemAdapter videoStreamsAdapter; private StreamItemAdapter 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) { diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 43e22d597..9ad734cb5 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -109,54 +109,55 @@ public class VideoDetailFragment extends BaseStateFragment 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".
- * The peek is the current video. - */ - private final LinkedList 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 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 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".
+ * The peek is the current video. + */ + private final LinkedList 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 return instance; } + + /*////////////////////////////////////////////////////////////////////////// + // Fragment's Lifecycle + //////////////////////////////////////////////////////////////////////////*/ + @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -285,10 +303,6 @@ public class VideoDetailFragment extends BaseStateFragment disposables = null; } - /*////////////////////////////////////////////////////////////////////////// - // State Saving - //////////////////////////////////////////////////////////////////////////*/ - @Override public void onDestroyView() { if (DEBUG) { @@ -336,6 +350,10 @@ public class VideoDetailFragment extends BaseStateFragment } } + /*////////////////////////////////////////////////////////////////////////// + // State Saving + //////////////////////////////////////////////////////////////////////////*/ + @Override public void onSaveInstanceState(final Bundle outState) { super.onSaveInstanceState(outState); @@ -351,10 +369,6 @@ public class VideoDetailFragment extends BaseStateFragment 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 //noinspection unchecked stack.addAll((Collection) serializable); } - } + /*////////////////////////////////////////////////////////////////////////// + // OnClick + //////////////////////////////////////////////////////////////////////////*/ + @Override public void onClick(final View v) { if (isLoading.get() || currentInfo == null) { @@ -449,10 +466,6 @@ public class VideoDetailFragment extends BaseStateFragment return true; } - /*////////////////////////////////////////////////////////////////////////// - // Init - //////////////////////////////////////////////////////////////////////////*/ - private void toggleTitleAndDescription() { if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) { videoTitleTextView.setMaxLines(1); @@ -465,6 +478,10 @@ public class VideoDetailFragment extends BaseStateFragment } } + /*////////////////////////////////////////////////////////////////////////// + // Init + //////////////////////////////////////////////////////////////////////////*/ + @Override protected void initViews(final View rootView, final Bundle savedInstanceState) { super.initViews(rootView, savedInstanceState); @@ -553,11 +570,6 @@ public class VideoDetailFragment extends BaseStateFragment }; } - - /*////////////////////////////////////////////////////////////////////////// - // 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 } } + /*////////////////////////////////////////////////////////////////////////// + // Menu + //////////////////////////////////////////////////////////////////////////*/ + @Override public void onCreateOptionsMenu(final Menu m, final MenuInflater inflater) { this.menu = m; @@ -654,10 +670,6 @@ public class VideoDetailFragment extends BaseStateFragment 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 }); } - 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 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 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 } - protected void prepareAndLoadInfo() { + private void prepareAndLoadInfo() { appBarLayout.setExpanded(true, true); pushToStack(serviceId, url, name); startLoading(false); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java index 68937f078..55301dd50 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java @@ -44,20 +44,22 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView; public abstract class BaseListFragment extends BaseStateFragment implements ListViewContract, 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 extends BaseStateFragment .registerOnSharedPreferenceChangeListener(this); } - /*////////////////////////////////////////////////////////////////////////// - // State Saving - //////////////////////////////////////////////////////////////////////////*/ - @Override public void onDestroy() { super.onDestroy(); @@ -111,6 +109,10 @@ public abstract class BaseListFragment extends BaseStateFragment } } + /*////////////////////////////////////////////////////////////////////////// + // State Saving + //////////////////////////////////////////////////////////////////////////*/ + /** * If the default implementation of {@link StateSaver.WriteRead} should be used. * diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index 0cd7fe32c..8c93ee293 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -70,6 +70,7 @@ public class ChannelFragment extends BaseListInfoFragment { /*////////////////////////////////////////////////////////////////////////// // Views //////////////////////////////////////////////////////////////////////////*/ + private SubscriptionManager subscriptionManager; private View headerRootLayout; private ImageView headerChannelBanner; @@ -83,10 +84,6 @@ public class ChannelFragment extends BaseListInfoFragment { 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 { } } + /*////////////////////////////////////////////////////////////////////////// + // LifeCycle + //////////////////////////////////////////////////////////////////////////*/ + @Override public void onAttach(final Context context) { super.onAttach(context); @@ -117,10 +118,6 @@ public class ChannelFragment extends BaseListInfoFragment { 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 { } /*////////////////////////////////////////////////////////////////////////// - // Menu + // Init //////////////////////////////////////////////////////////////////////////*/ protected View getListHeader() { @@ -154,6 +151,10 @@ public class ChannelFragment extends BaseListInfoFragment { 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 { } } - /*////////////////////////////////////////////////////////////////////////// - // Channel Subscription - //////////////////////////////////////////////////////////////////////////*/ - @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { @@ -208,6 +205,10 @@ public class ChannelFragment extends BaseListInfoFragment { return true; } + /*////////////////////////////////////////////////////////////////////////// + // Channel Subscription + //////////////////////////////////////////////////////////////////////////*/ + private void monitorSubscription(final ChannelInfo info) { final Consumer onError = (Throwable throwable) -> { animateView(headerSubscribeButton, false, 100); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java index 68836bbd0..e3eac27ca 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java @@ -294,7 +294,7 @@ public class PlaylistFragment extends BaseListInfoFragment { } }); } - } else { // Else say we have no uploader + } else { // Otherwise say we have no uploader headerUploaderName.setText(R.string.playlist_no_uploader); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java index ce84c1b57..718865f10 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java @@ -80,7 +80,6 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView; public class SearchFragment extends BaseListFragment implements BackPressable { - /*////////////////////////////////////////////////////////////////////////// // Search //////////////////////////////////////////////////////////////////////////*/ @@ -97,35 +96,45 @@ public class SearchFragment extends BaseListFragment 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 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 objectsToSave) { super.writeTo(objectsToSave); @@ -358,10 +368,6 @@ public class SearchFragment extends BaseListFragment> getPlaylistsSubscriber() { return new Subscriber>() { @Override @@ -229,9 +229,6 @@ public final class BookmarkFragment extends BaseLocalListFragment result) { @@ -252,6 +249,10 @@ public final class BookmarkFragment extends BaseLocalListFragment> getHistoryObserver() { return new Subscriber>() { @Override @@ -294,10 +298,6 @@ public class StatisticsPlaylistFragment }; } - /////////////////////////////////////////////////////////////////////////// - // Statistics Loader - /////////////////////////////////////////////////////////////////////////// - @Override public void handleResult(@NonNull final List 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)); } diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java index c0b7b0ec2..d430afa5c 100644 --- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java @@ -56,12 +56,14 @@ public class LocalPlaylistFragment extends BaseLocalListFragment 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; } diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java b/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java index cdabea2cb..16cd70cf2 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/services/BaseImportExportService.java @@ -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 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 diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsImportService.java b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsImportService.java index 379df7151..70d061d7e 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsImportService.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsImportService.java @@ -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); diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index d4a7e7851..601fd96bf 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -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 //////////////////////////////////////////////////////////////////////////*/ diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index 47ea9f4e3..6656ec29e 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -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 diff --git a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java index 3a33772d6..6841389f4 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java +++ b/app/src/main/java/org/schabi/newpipe/player/ServicePlayerActivity.java @@ -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; diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java index b75d39b84..7e74a6ee2 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -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 availableStreams; + private int selectedStreamIndex; + + protected boolean wasPlaying = false; + /*////////////////////////////////////////////////////////////////////////// // Views //////////////////////////////////////////////////////////////////////////*/ - private final int captionPopupMenuGroupId = 89; - protected boolean wasPlaying = false; - boolean isSomePopupMenuVisible = false; - private List 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); diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/CacheFactory.java b/app/src/main/java/org/schabi/newpipe/player/helper/CacheFactory.java index dc3d9d269..2ef22f2eb 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/CacheFactory.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/CacheFactory.java @@ -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, diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java index 089ea456e..0d511d565 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java @@ -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); diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java index bc8955e74..db98ee6d3 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java @@ -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) diff --git a/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java b/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java index 7bc9c34cc..af89d3f3d 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java @@ -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. - *

+ *

* The streams after the current will be loaded into the playlist timeline while the * streams before will only be cached for future usage. + *

* * @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 nearEndIntervalSignal; + /** * Process only the last load order when receiving a stream of load orders (lessens I/O). - *

+ *

* The higher it is, the less loading occurs during rapid noncritical timeline changes. - *

+ *

+ *

* Not recommended to go below 100ms. + *

* * @see #loadDebounced() */ private final long loadDebounceMillis; + @NonNull private final Disposable debouncedLoader; @NonNull private final PublishSubject debouncedSignal; + + @NonNull + private Subscription playQueueReactor; + @NonNull private final CompositeDisposable loaderReactor; @NonNull private final Set 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 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 getReactor() { return new Subscriber() { @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 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 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; diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/AbstractInfoPlayQueue.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/AbstractInfoPlayQueue.java index 9c77a6ef5..f0d6dc6ec 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playqueue/AbstractInfoPlayQueue.java +++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/AbstractInfoPlayQueue.java @@ -16,10 +16,11 @@ import io.reactivex.annotations.NonNull; import io.reactivex.disposables.Disposable; abstract class AbstractInfoPlayQueue 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 ext this.isComplete = !isInitial && (nextPageUrl == null || nextPageUrl.isEmpty()); } - private static List extractListItems(final List infos) { - List 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 ext } fetchReactor = null; } + + private static List extractListItems(final List infos) { + List result = new ArrayList<>(); + for (final InfoItem stream : infos) { + if (stream instanceof StreamInfoItem) { + result.add(new PlayQueueItem((StreamInfoItem) stream)); + } + } + return result; + } } diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java index 84ef45242..7de1d6422 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java +++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java @@ -36,17 +36,22 @@ import io.reactivex.subjects.BehaviorSubject; *

* 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. + *

*

* This class can be serialized for passing intents, but in order to start the * message bus, it must be initialized. + *

*/ 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 backup; private ArrayList streams; + + @NonNull + private final AtomicInteger queueIndex; + private transient BehaviorSubject eventBroadcast; private transient Flowable broadcastReceiver; private transient Subscription reportingReactor; diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueAdapter.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueAdapter.java index 8028a5a9d..bf1361fc5 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueAdapter.java @@ -28,19 +28,23 @@ import io.reactivex.disposables.Disposable; *

* Copyright (C) Christian Schabesberger 2016 * InfoListAdapter.java is part of NewPipe. + *

*

* 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. + *

*

* 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. + *

*

* You should have received a copy of the GNU General Public License * along with NewPipe. If not, see . + *

*/ public class PlayQueueAdapter extends RecyclerView.Adapter { diff --git a/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java b/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java index 3c131454d..2eb766769 100644 --- a/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java +++ b/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java @@ -32,6 +32,7 @@ public class VideoPlaybackResolver implements PlaybackResolver { private final PlayerDataSource dataSource; @NonNull private final QualityResolver qualityResolver; + @Nullable private String playbackQuality; diff --git a/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java index 19bf9d14d..46a816029 100644 --- a/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java +++ b/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java @@ -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 getReturnActivity(final Class returnActivity) { - Class 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 getReturnActivity(final Class returnActivity) { + Class 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 checkedReturnActivity = getReturnActivity(returnActivity); if (checkedReturnActivity == null) { diff --git a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java index 1242c39e8..03e246533 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java @@ -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 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 { private final LayoutInflater inflater; diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java index 2621a38e5..9ac3e2eda 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java @@ -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 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 newSubscriptions) { this.subscriptions = newSubscriptions; progressBar.setVisibility(View.GONE); @@ -141,10 +144,6 @@ public class SelectChannelFragment extends DialogFragment { } - /*////////////////////////////////////////////////////////////////////////// - // Item handling - //////////////////////////////////////////////////////////////////////////*/ - private Observer> getSubscriptionObserver() { return new Observer>() { @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 { @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; diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java index 014e108f9..cb148c843 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SelectKioskFragment.java @@ -50,9 +50,6 @@ public class SelectKioskFragment extends DialogFragment { private RecyclerView recyclerView = null; private SelectKioskAdapter selectKioskAdapter = null; - /*////////////////////////////////////////////////////////////////////////// - // Interfaces - //////////////////////////////////////////////////////////////////////////*/ private OnSelectedLisener onSelectedLisener = null; private OnCancelListener onCancelListener = null; @@ -80,6 +77,10 @@ public class SelectKioskFragment extends DialogFragment { return v; } + /*////////////////////////////////////////////////////////////////////////// + // Handle actions + //////////////////////////////////////////////////////////////////////////*/ + @Override public void onCancel(final DialogInterface dialogInterface) { super.onCancel(dialogInterface); @@ -95,8 +96,8 @@ public class SelectKioskFragment extends DialogFragment { dismiss(); } - /*////////////////////////////////////////////////////////////////////////// - // Handle actions + /*////////////////////////////////////////////////////////////////////////// + // Error //////////////////////////////////////////////////////////////////////////*/ protected void onError(final Throwable e) { @@ -105,6 +106,10 @@ public class SelectKioskFragment extends DialogFragment { .make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash)); } + /*////////////////////////////////////////////////////////////////////////// + // Interfaces + //////////////////////////////////////////////////////////////////////////*/ + public interface OnSelectedLisener { void onKioskSelected(int serviceId, String kioskId, String kioskName); } @@ -113,10 +118,6 @@ public class SelectKioskFragment extends DialogFragment { void onCancel(); } - /*////////////////////////////////////////////////////////////////////////// - // Error - //////////////////////////////////////////////////////////////////////////*/ - private class SelectKioskAdapter extends RecyclerView.Adapter { private final List kioskList = new Vector<>(); diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java index aafc05240..8a3a7f67e 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/ChooseTabsFragment.java @@ -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 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 returnList = new ArrayList<>(); for (Tab.Type type : Tab.Type.values()) { diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java index ef4e35aef..07e1c1cc3 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java @@ -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(); diff --git a/app/src/main/java/org/schabi/newpipe/settings/tabs/TabsManager.java b/app/src/main/java/org/schabi/newpipe/settings/tabs/TabsManager.java index 4c8e0c06b..c76df7047 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/tabs/TabsManager.java +++ b/app/src/main/java/org/schabi/newpipe/settings/tabs/TabsManager.java @@ -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(); } - } - - - - - - - diff --git a/app/src/main/java/org/schabi/newpipe/util/InfoCache.java b/app/src/main/java/org/schabi/newpipe/util/InfoCache.java index 03eae344a..035416dcd 100644 --- a/app/src/main/java/org/schabi/newpipe/util/InfoCache.java +++ b/app/src/main/java/org/schabi/newpipe/util/InfoCache.java @@ -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 LRU_CACHE = new LruCache<>(MAX_ITEMS_ON_CACHE); - private final String TAG = getClass().getSimpleName(); private InfoCache() { - //no instance + // no instance } public static InfoCache getInstance() { diff --git a/app/src/main/java/org/schabi/newpipe/views/CollapsibleView.java b/app/src/main/java/org/schabi/newpipe/views/CollapsibleView.java index 71fc37e93..028e9b674 100644 --- a/app/src/main/java/org/schabi/newpipe/views/CollapsibleView.java +++ b/app/src/main/java/org/schabi/newpipe/views/CollapsibleView.java @@ -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 listeners = new ArrayList<>(); @State @ViewMode int currentState = COLLAPSED; - - /*////////////////////////////////////////////////////////////////////////// - // Collapse/expand logic - //////////////////////////////////////////////////////////////////////////*/ private boolean readyToChangeState; + private int targetHeight = -1; private ValueAnimator currentAnimator; + private final List 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 must 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}.