From 08127e5806c2234034af9b61650b8f7f9aae3b9d Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Mon, 3 Sep 2018 04:52:59 +0530 Subject: [PATCH 01/37] added basic/crappy comments support --- app/build.gradle | 2 +- .../java/org/schabi/newpipe/Downloader.java | 101 +++++++- .../fragments/detail/VideoDetailFragment.java | 222 +++++++++++++++--- .../fragments/list/BaseListFragment.java | 8 + .../newpipe/info_list/InfoItemBuilder.java | 14 ++ .../newpipe/info_list/InfoListAdapter.java | 5 + .../holder/CommentsInfoItemHolder.java | 53 +++++ .../holder/CommentsMiniInfoItemHolder.java | 92 ++++++++ .../schabi/newpipe/util/ExtractorHelper.java | 34 +-- .../main/res/layout/fragment_video_detail.xml | 206 ++++++++++------ .../main/res/layout/list_comments_item.xml | 112 +++++++++ .../res/layout/list_comments_mini_item.xml | 112 +++++++++ app/src/main/res/values/settings_keys.xml | 1 + app/src/main/res/values/strings.xml | 1 + 14 files changed, 834 insertions(+), 129 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsInfoItemHolder.java create mode 100644 app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java create mode 100644 app/src/main/res/layout/list_comments_item.xml create mode 100644 app/src/main/res/layout/list_comments_mini_item.xml diff --git a/app/build.gradle b/app/build.gradle index 4ae9f0fb7..d409532bb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,7 +55,7 @@ dependencies { exclude module: 'support-annotations' } - implementation 'com.github.TeamNewPipe:NewPipeExtractor:217d13b1028' + implementation 'com.github.yausername:NewPipeExtractor:5242bda' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.8.9' diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index 17dc5859d..d51d31e11 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -3,17 +3,22 @@ package org.schabi.newpipe; import android.support.annotation.Nullable; import android.text.TextUtils; +import org.schabi.newpipe.extractor.DownloadResponse; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; import java.io.IOException; import java.io.InputStream; +import java.io.Serializable; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; +import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; +import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; @@ -137,13 +142,16 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader { private ResponseBody getBody(String siteUrl, Map customProperties) throws IOException, ReCaptchaException { final Request.Builder requestBuilder = new Request.Builder() - .method("GET", null).url(siteUrl) - .addHeader("User-Agent", USER_AGENT); + .method("GET", null).url(siteUrl); for (Map.Entry header : customProperties.entrySet()) { requestBuilder.addHeader(header.getKey(), header.getValue()); } + if (!customProperties.containsKey("User-Agent")) { + requestBuilder.header("User-Agent", USER_AGENT); + } + if (!TextUtils.isEmpty(mCookies)) { requestBuilder.addHeader("Cookie", mCookies); } @@ -175,4 +183,91 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader { public String download(String siteUrl) throws IOException, ReCaptchaException { return download(siteUrl, Collections.emptyMap()); } -} + + + @Override + public DownloadResponse get(String siteUrl, Map> requestHeaders) throws IOException, ReCaptchaException { + final Request.Builder requestBuilder = new Request.Builder() + .method("GET", null).url(siteUrl); + + // set custom headers in request + for (Map.Entry> pair : requestHeaders.entrySet()) { + for(String value : pair.getValue()){ + requestBuilder.addHeader(pair.getKey(), value); + } + } + + if (!requestHeaders.containsKey("User-Agent")) { + requestBuilder.header("User-Agent", USER_AGENT); + } + + if (!TextUtils.isEmpty(mCookies)) { + requestBuilder.addHeader("Cookie", mCookies); + } + + final Request request = requestBuilder.build(); + final Response response = client.newCall(request).execute(); + final ResponseBody body = response.body(); + + if (response.code() == 429) { + throw new ReCaptchaException("reCaptcha Challenge requested"); + } + + if (body == null) { + response.close(); + return null; + } + + return new DownloadResponse(body.string(), response.headers().toMultimap()); + } + + @Override + public DownloadResponse get(String siteUrl) throws IOException, ReCaptchaException { + return get(siteUrl, Collections.emptyMap()); + } + + @Override + public DownloadResponse post(String siteUrl, String requestBody, Map> requestHeaders) throws IOException, ReCaptchaException { + + if(null == requestHeaders.get("Content-Type") || requestHeaders.get("Content-Type").isEmpty()){ + // content type header is required. maybe throw an exception here + return null; + } + + String contentType = requestHeaders.get("Content-Type").get(0); + + RequestBody okRequestBody = RequestBody.create(MediaType.parse(contentType), requestBody); + final Request.Builder requestBuilder = new Request.Builder() + .method("POST", okRequestBody).url(siteUrl); + + // set custom headers in request + for (Map.Entry> pair : requestHeaders.entrySet()) { + for(String value : pair.getValue()){ + requestBuilder.addHeader(pair.getKey(), value); + } + } + + if (!requestHeaders.containsKey("User-Agent")) { + requestBuilder.header("User-Agent", USER_AGENT); + } + + if (!TextUtils.isEmpty(mCookies)) { + requestBuilder.addHeader("Cookie", mCookies); + } + + final Request request = requestBuilder.build(); + final Response response = client.newCall(request).execute(); + final ResponseBody body = response.body(); + + if (response.code() == 429) { + throw new ReCaptchaException("reCaptcha Challenge requested"); + } + + if (body == null) { + response.close(); + return null; + } + + return new DownloadResponse(body.string(), response.headers().toMultimap()); + } +} \ No newline at end of file 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 c726f8cee..cbea6803e 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 @@ -40,6 +40,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.Spinner; +import android.widget.TabHost; import android.widget.TextView; import android.widget.Toast; @@ -53,6 +54,7 @@ import org.schabi.newpipe.ReCaptchaActivity; import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.comments.CommentsInfoItem; import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; @@ -64,19 +66,17 @@ import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.fragments.BackPressable; import org.schabi.newpipe.fragments.BaseStateFragment; -import org.schabi.newpipe.local.history.HistoryRecordManager; -import org.schabi.newpipe.report.ErrorActivity; -import org.schabi.newpipe.util.StreamItemAdapter; -import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper; -import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemDialog; +import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; +import org.schabi.newpipe.local.history.HistoryRecordManager; import org.schabi.newpipe.player.MainVideoPlayer; import org.schabi.newpipe.player.PopupVideoPlayer; import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.old.PlayVideoActivity; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue; +import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.ExtractorHelper; @@ -87,6 +87,8 @@ import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.PermissionHelper; +import org.schabi.newpipe.util.StreamItemAdapter; +import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper; import org.schabi.newpipe.util.ThemeHelper; import java.io.Serializable; @@ -114,6 +116,8 @@ public class VideoDetailFragment // Amount of videos to show on start private static final int INITIAL_RELATED_VIDEOS = 8; + // Amount of comments to show on start + private static final int INITIAL_COMMENTS = 8; private InfoItemBuilder infoItemBuilder = null; @@ -121,18 +125,24 @@ public class VideoDetailFragment 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 = 0x4; private boolean autoPlayEnabled; private boolean showRelatedStreams; + private boolean showComments; private boolean wasRelatedStreamsExpanded = false; - @State protected int serviceId = Constants.NO_SERVICE_ID; - @State protected String name; - @State protected String url; + @State + protected int serviceId = Constants.NO_SERVICE_ID; + @State + protected String name; + @State + protected String url; private StreamInfo currentInfo; private Disposable currentWorker; - @NonNull private CompositeDisposable disposables = new CompositeDisposable(); + @NonNull + private CompositeDisposable disposables = new CompositeDisposable(); private List sortedVideoStreams; private int selectedVideoStreamIndex = -1; @@ -183,6 +193,16 @@ public class VideoDetailFragment private LinearLayout relatedStreamsView; private ImageButton relatedStreamExpandButton; + private LinearLayout commentsRootLayout; + private LinearLayout commentsView; + private ImageButton commentsExpandButton; + private Disposable commentsDisposable; + + private TabHost tabHost; + private static final String COMMENTS_TAB_TAG = "CommentsTab"; + private static final String RELATED_TAB_TAG = "RelatedTab"; + + /*////////////////////////////////////////////////////////////////////////*/ @@ -197,12 +217,17 @@ public class VideoDetailFragment //////////////////////////////////////////////////////////////////////////*/ @Override - public void onCreate(Bundle savedInstanceState) { + public void + onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); showRelatedStreams = PreferenceManager.getDefaultSharedPreferences(activity) .getBoolean(getString(R.string.show_next_video_key), true); + + showComments = PreferenceManager.getDefaultSharedPreferences(activity) + .getBoolean(getString(R.string.show_comments), true); + PreferenceManager.getDefaultSharedPreferences(activity) .registerOnSharedPreferenceChangeListener(this); } @@ -224,14 +249,17 @@ public class VideoDetailFragment if (updateFlags != 0) { if (!isLoading.get() && currentInfo != null) { - if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) initRelatedVideos(currentInfo); + if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) + initRelatedVideos(currentInfo); if ((updateFlags & RESOLUTIONS_MENU_UPDATE_FLAG) != 0) setupActionBar(currentInfo); + if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) initComments(currentInfo); } if ((updateFlags & TOOLBAR_ITEMS_UPDATE_FLAG) != 0 && menu != null) { updateMenuItemVisibility(); } + updateFlags = 0; } @@ -288,6 +316,9 @@ public class VideoDetailFragment updateFlags |= RESOLUTIONS_MENU_UPDATE_FLAG; } else if (key.equals(getString(R.string.show_play_with_kodi_key))) { updateFlags |= TOOLBAR_ITEMS_UPDATE_FLAG; + } else if (key.equals(R.string.show_comments)) { + showComments = sharedPreferences.getBoolean(key, true); + updateFlags |= COMMENTS_UPDATE_FLAG; } } @@ -312,7 +343,8 @@ public class VideoDetailFragment } if (!isLoading.get() && currentInfo != null && isVisible()) { - outState.putSerializable(INFO_KEY, currentInfo); + //TODO fix this. it should not be commented + //outState.putSerializable(INFO_KEY, currentInfo); } outState.putSerializable(STACK_KEY, stack); @@ -392,6 +424,9 @@ public class VideoDetailFragment case R.id.detail_related_streams_expand: toggleExpandRelatedVideos(currentInfo); break; + case R.id.detail_comments_expand: + toggleExpandComments(currentInfo); + break; } } @@ -452,6 +487,46 @@ public class VideoDetailFragment ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.collapse))); } + + private void toggleExpandComments(StreamInfo info) { + if (DEBUG) Log.d(TAG, "toggleExpandComments() called with: info = [" + info + "]"); + if (!showComments) return; + + int initialCount = INITIAL_COMMENTS; + + if (commentsView.getChildCount() > initialCount && commentsView.getChildCount() >= info.getComments().size() && !info.hasMoreComments()) { + commentsView.removeViews(initialCount, + commentsView.getChildCount() - (initialCount)); + commentsExpandButton.setImageDrawable(ContextCompat.getDrawable( + activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand))); + return; + } + + //Log.d(TAG, "toggleExpandRelatedVideos() called with: info = [" + info + "], from = [" + INITIAL_RELATED_VIDEOS + "]"); + int currentCount = commentsView.getChildCount(); + for (int i = currentCount; i < info.getComments().size(); i++) { + CommentsInfoItem item = info.getComments().get(i); + //Log.d(TAG, "i = " + i); + commentsView.addView(infoItemBuilder.buildView(commentsView, item)); + } + + if (info.hasMoreComments()) { + loadMoreComments(info); + } else { + commentsExpandButton.setImageDrawable( + ContextCompat.getDrawable(activity, + ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.collapse))); + } + } + + private void loadMoreComments(StreamInfo info) { + if (commentsDisposable != null) commentsDisposable.dispose(); + + commentsDisposable = Single.fromCallable(() -> { + StreamInfo.loadMoreComments(info); + return info.getComments(); + }).subscribeOn(Schedulers.io()).doOnError(e -> info.addError(e)).subscribe(); + } /*////////////////////////////////////////////////////////////////////////// // Init //////////////////////////////////////////////////////////////////////////*/ @@ -498,14 +573,37 @@ public class VideoDetailFragment uploaderTextView = rootView.findViewById(R.id.detail_uploader_text_view); uploaderThumb = rootView.findViewById(R.id.detail_uploader_thumbnail_view); + tabHost = (TabHost) rootView.findViewById(R.id.tab_host); + tabHost.setup(); + + TabHost.TabSpec commentsTab = tabHost.newTabSpec(COMMENTS_TAB_TAG); + commentsTab.setContent(R.id.detail_comments_root_layout); + commentsTab.setIndicator(getString(R.string.comments)); + + + TabHost.TabSpec relatedVideosTab = tabHost.newTabSpec(RELATED_TAB_TAG); + relatedVideosTab.setContent(R.id.detail_related_streams_root_layout); + relatedVideosTab.setIndicator(getString(R.string.next_video_title)); + + tabHost.addTab(commentsTab); + tabHost.addTab(relatedVideosTab); + + //show comments tab by default + tabHost.setCurrentTabByTag(COMMENTS_TAB_TAG); + relatedStreamRootLayout = rootView.findViewById(R.id.detail_related_streams_root_layout); nextStreamTitle = rootView.findViewById(R.id.detail_next_stream_title); relatedStreamsView = rootView.findViewById(R.id.detail_related_streams_view); - relatedStreamExpandButton = rootView.findViewById(R.id.detail_related_streams_expand); + commentsRootLayout = rootView.findViewById(R.id.detail_comments_root_layout); + commentsView = rootView.findViewById(R.id.detail_comments_view); + commentsExpandButton = rootView.findViewById(R.id.detail_comments_expand); + infoItemBuilder = new InfoItemBuilder(activity); setHeightThumbnail(); + + } @Override @@ -532,6 +630,7 @@ public class VideoDetailFragment detailControlsDownload.setOnClickListener(this); detailControlsDownload.setOnLongClickListener(this); relatedStreamExpandButton.setOnClickListener(this); + commentsExpandButton.setOnClickListener(this); detailControlsBackground.setLongClickable(true); detailControlsPopup.setLongClickable(true); @@ -622,7 +721,7 @@ public class VideoDetailFragment relatedStreamsView.addView( infoItemBuilder.buildView(relatedStreamsView, info.getNextVideo())); relatedStreamsView.addView(getSeparatorView()); - relatedStreamRootLayout.setVisibility(View.VISIBLE); + showRelatedStreamsIfSelected(); } else nextStreamTitle.setVisibility(View.GONE); if (info.getRelatedStreams() != null @@ -639,7 +738,7 @@ public class VideoDetailFragment } //if (DEBUG) Log.d(TAG, "Total time " + ((System.nanoTime() - first) / 1000000L) + "ms"); - relatedStreamRootLayout.setVisibility(View.VISIBLE); + showRelatedStreamsIfSelected(); relatedStreamExpandButton.setVisibility(View.VISIBLE); relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable( @@ -648,6 +747,47 @@ public class VideoDetailFragment if (info.getNextVideo() == null) relatedStreamRootLayout.setVisibility(View.GONE); relatedStreamExpandButton.setVisibility(View.GONE); } + + } + + private void showRelatedStreamsIfSelected() { + if (tabHost.getCurrentTabTag().contentEquals(RELATED_TAB_TAG)) { + relatedStreamRootLayout.setVisibility(View.VISIBLE); + } + } + + private void initComments(StreamInfo info) { + if (commentsView.getChildCount() > 0) commentsView.removeAllViews(); + + if (info.getComments() != null + && !info.getComments().isEmpty() && showComments) { + //long first = System.nanoTime(), each; + int to = info.getComments().size() >= INITIAL_RELATED_VIDEOS + ? INITIAL_RELATED_VIDEOS + : info.getComments().size(); + for (int i = 0; i < to; i++) { + InfoItem item = info.getComments().get(i); + //each = System.nanoTime(); + commentsView.addView(infoItemBuilder.buildView(commentsView, item)); + //if (DEBUG) Log.d(TAG, "each took " + ((System.nanoTime() - each) / 1000000L) + "ms"); + } + //if (DEBUG) Log.d(TAG, "Total time " + ((System.nanoTime() - first) / 1000000L) + "ms"); + + showCommentsIfSelected(); + commentsExpandButton.setVisibility(View.VISIBLE); + + commentsExpandButton.setImageDrawable(ContextCompat.getDrawable( + activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand))); + } else { + commentsRootLayout.setVisibility(View.GONE); + } + + } + + private void showCommentsIfSelected() { + if (tabHost.getCurrentTabTag().contentEquals(COMMENTS_TAB_TAG)) { + commentsRootLayout.setVisibility(View.VISIBLE); + } } /*////////////////////////////////////////////////////////////////////////// @@ -682,7 +822,7 @@ public class VideoDetailFragment @Override public boolean onOptionsItemSelected(MenuItem item) { - if(isLoading.get()) { + if (isLoading.get()) { // if is still loading block menu return true; } @@ -706,7 +846,7 @@ public class VideoDetailFragment NavigationHelper.playWithKore(activity, Uri.parse( url.replace("https", "http"))); } catch (Exception e) { - if(DEBUG) Log.i(TAG, "Failed to start kore", e); + if (DEBUG) Log.i(TAG, "Failed to start kore", e); showInstallKoreDialog(activity); } return true; @@ -720,7 +860,8 @@ public class VideoDetailFragment builder.setMessage(R.string.kore_not_found) .setPositiveButton(R.string.install, (DialogInterface dialog, int which) -> NavigationHelper.installKore(context)) - .setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {}); + .setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> { + }); builder.create().show(); } @@ -823,7 +964,8 @@ public class VideoDetailFragment } public void prepareAndHandleInfo(final StreamInfo info, boolean scrollToTop) { - if (DEBUG) Log.d(TAG, "prepareAndHandleInfo() called with: info = [" + info + "], scrollToTop = [" + scrollToTop + "]"); + if (DEBUG) + Log.d(TAG, "prepareAndHandleInfo() called with: info = [" + info + "], scrollToTop = [" + scrollToTop + "]"); setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName()); pushToStack(serviceId, url, name); @@ -1057,7 +1199,7 @@ public class VideoDetailFragment .setInterpolator(new FastOutSlowInInterpolator()) .start(); - if (showRelatedStreams) { + if (showRelatedStreams && tabHost.getCurrentTabTag().contentEquals(RELATED_TAB_TAG)) { relatedStreamRootLayout.animate().setListener(null).cancel(); relatedStreamRootLayout.setAlpha(0f); relatedStreamRootLayout.setTranslationY(translationY); @@ -1070,6 +1212,20 @@ public class VideoDetailFragment .setInterpolator(new FastOutSlowInInterpolator()) .start(); } + + if (showComments && tabHost.getCurrentTabTag().contentEquals(COMMENTS_TAB_TAG)) { + commentsRootLayout.animate().setListener(null).cancel(); + commentsRootLayout.setAlpha(0f); + commentsRootLayout.setTranslationY(translationY); + commentsRootLayout.setVisibility(View.VISIBLE); + commentsRootLayout.animate() + .alpha(1f) + .translationY(0) + .setStartDelay((long) (duration * .8f) + delay) + .setDuration(duration) + .setInterpolator(new FastOutSlowInInterpolator()) + .start(); + } } protected void setInitialData(int serviceId, String url, String name) { @@ -1204,6 +1360,8 @@ public class VideoDetailFragment setupActionBar(info); initThumbnailViews(info); initRelatedVideos(info); + initComments(info); + if (wasRelatedStreamsExpanded) { toggleExpandRelatedVideos(currentInfo); wasRelatedStreamsExpanded = false; @@ -1246,19 +1404,19 @@ public class VideoDetailFragment public void openDownloadDialog() { - try { - DownloadDialog downloadDialog = DownloadDialog.newInstance(currentInfo); - downloadDialog.setVideoStreams(sortedVideoStreams); - downloadDialog.setAudioStreams(currentInfo.getAudioStreams()); - downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex); + try { + DownloadDialog downloadDialog = DownloadDialog.newInstance(currentInfo); + downloadDialog.setVideoStreams(sortedVideoStreams); + downloadDialog.setAudioStreams(currentInfo.getAudioStreams()); + downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex); - downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog"); - } catch (Exception e) { - Toast.makeText(activity, - R.string.could_not_setup_download_menu, - Toast.LENGTH_LONG).show(); - e.printStackTrace(); - } + downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog"); + } catch (Exception e) { + Toast.makeText(activity, + R.string.could_not_setup_download_menu, + Toast.LENGTH_LONG).show(); + e.printStackTrace(); + } } /*////////////////////////////////////////////////////////////////////////// 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 c70ea2b19..cd557c931 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 @@ -17,6 +17,7 @@ import android.view.View; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem; +import org.schabi.newpipe.extractor.comments.CommentsInfoItem; import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.fragments.BaseStateFragment; @@ -181,6 +182,13 @@ public abstract class BaseListFragment extends BaseStateFragment implem } }); + infoListAdapter.setOnCommentsSelectedListener(new OnClickGesture() { + @Override + public void selected(CommentsInfoItem selectedItem) { + //Log.d("comments" , "this comment was clicked" + selectedItem.getCommentText()); + } + }); + itemsList.clearOnScrollListeners(); itemsList.addOnScrollListener(new OnScrollBelowItemsListener() { @Override diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java index 78867c81f..dbb91bbb2 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java @@ -10,10 +10,13 @@ import com.nostra13.universalimageloader.core.ImageLoader; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem; +import org.schabi.newpipe.extractor.comments.CommentsInfoItem; import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder; import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder; +import org.schabi.newpipe.info_list.holder.CommentsInfoItemHolder; +import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder; import org.schabi.newpipe.info_list.holder.InfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder; @@ -50,6 +53,7 @@ public class InfoItemBuilder { private OnClickGesture onStreamSelectedListener; private OnClickGesture onChannelSelectedListener; private OnClickGesture onPlaylistSelectedListener; + private OnClickGesture onCommentsSelectedListener; public InfoItemBuilder(Context context) { this.context = context; @@ -73,6 +77,8 @@ public class InfoItemBuilder { return useMiniVariant ? new ChannelMiniInfoItemHolder(this, parent) : new ChannelInfoItemHolder(this, parent); case PLAYLIST: return useMiniVariant ? new PlaylistMiniInfoItemHolder(this, parent) : new PlaylistInfoItemHolder(this, parent); + case COMMENT: + return useMiniVariant ? new CommentsMiniInfoItemHolder(this, parent) : new CommentsInfoItemHolder(this, parent); default: Log.e(TAG, "Trollolo"); throw new RuntimeException("InfoType not expected = " + infoType.name()); @@ -111,4 +117,12 @@ public class InfoItemBuilder { this.onPlaylistSelectedListener = listener; } + public OnClickGesture getOnCommentsSelectedListener() { + return onCommentsSelectedListener; + } + + public void setOnCommentsSelectedListener(OnClickGesture onCommentsSelectedListener) { + this.onCommentsSelectedListener = onCommentsSelectedListener; + } + } diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java index cf12deb6f..49bd2bdf1 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java @@ -8,6 +8,7 @@ import android.view.ViewGroup; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem; +import org.schabi.newpipe.extractor.comments.CommentsInfoItem; import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder; @@ -90,6 +91,10 @@ public class InfoListAdapter extends RecyclerView.Adapter listener) { + infoItemBuilder.setOnCommentsSelectedListener(listener); + } + public void useMiniItemVariants(boolean useMiniVariant) { this.useMiniVariant = useMiniVariant; } diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsInfoItemHolder.java new file mode 100644 index 000000000..46e4b4563 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsInfoItemHolder.java @@ -0,0 +1,53 @@ +package org.schabi.newpipe.info_list.holder; + +import android.view.ViewGroup; +import android.widget.TextView; + +import org.schabi.newpipe.R; +import org.schabi.newpipe.extractor.InfoItem; +import org.schabi.newpipe.extractor.channel.ChannelInfoItem; +import org.schabi.newpipe.extractor.comments.CommentsInfoItem; +import org.schabi.newpipe.info_list.InfoItemBuilder; +import org.schabi.newpipe.util.Localization; + +/* + * Created by Christian Schabesberger on 12.02.17. + * + * Copyright (C) Christian Schabesberger 2016 + * ChannelInfoItemHolder .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 CommentsInfoItemHolder extends CommentsMiniInfoItemHolder { + + public final TextView itemTitleView; + + public CommentsInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) { + super(infoItemBuilder, R.layout.list_comments_item, parent); + + itemTitleView = itemView.findViewById(R.id.itemTitleView); + } + + @Override + public void updateFromItem(final InfoItem infoItem) { + super.updateFromItem(infoItem); + + if (!(infoItem instanceof CommentsInfoItem)) return; + final CommentsInfoItem item = (CommentsInfoItem) infoItem; + + itemTitleView.setText(item.getAuthorName()); + } + +} diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java new file mode 100644 index 000000000..046cadc3f --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java @@ -0,0 +1,92 @@ +package org.schabi.newpipe.info_list.holder; + +import android.support.v7.app.AppCompatActivity; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.schabi.newpipe.R; +import org.schabi.newpipe.extractor.InfoItem; +import org.schabi.newpipe.extractor.comments.CommentsInfoItem; +import org.schabi.newpipe.info_list.InfoItemBuilder; +import org.schabi.newpipe.report.ErrorActivity; +import org.schabi.newpipe.util.ImageDisplayConstants; +import org.schabi.newpipe.util.Localization; +import org.schabi.newpipe.util.NavigationHelper; + +import de.hdodenhof.circleimageview.CircleImageView; + +public class CommentsMiniInfoItemHolder extends InfoItemHolder { + public final CircleImageView itemThumbnailView; + private final TextView itemContentView; + private final TextView itemLikesCountView; + private final TextView itemDislikesCountView; + + private static final int commentDefaultLines = 2; + private static final int commentExpandedLines = 1000; + + CommentsMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) { + super(infoItemBuilder, layoutId, parent); + + itemThumbnailView = itemView.findViewById(R.id.itemThumbnailView); + itemContentView = itemView.findViewById(R.id.itemCommentContentView); + itemLikesCountView = itemView.findViewById(R.id.detail_thumbs_up_count_view); + itemDislikesCountView = itemView.findViewById(R.id.detail_thumbs_down_count_view); + } + + public CommentsMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) { + this(infoItemBuilder, R.layout.list_comments_mini_item, parent); + } + + @Override + public void updateFromItem(final InfoItem infoItem) { + if (!(infoItem instanceof CommentsInfoItem)) return; + final CommentsInfoItem item = (CommentsInfoItem) infoItem; + + itemBuilder.getImageLoader() + .displayImage(item.getAuthorThumbnail(), + itemThumbnailView, + ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS); + + itemThumbnailView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + try { + final AppCompatActivity activity = (AppCompatActivity) itemBuilder.getContext(); + NavigationHelper.openChannelFragment( + activity.getSupportFragmentManager(), + item.getServiceId(), + item.getAuthorEndpoint(), + item.getAuthorName()); + } catch (Exception e) { + ErrorActivity.reportUiError((AppCompatActivity) itemBuilder.getContext(), e); + } + } + }); + + itemContentView.setText(item.getCommentText()); + if (null != item.getLikeCount()) { + itemLikesCountView.setText(String.valueOf(item.getLikeCount())); + } + + itemView.setOnClickListener(view -> { + toggleEllipsize(item.getCommentText()); + if (itemBuilder.getOnCommentsSelectedListener() != null) { + itemBuilder.getOnCommentsSelectedListener().selected(item); + } + }); + } + + private void toggleEllipsize(String text) { + // toggle ellipsize + if (null == itemContentView.getEllipsize()) { + itemContentView.setEllipsize(TextUtils.TruncateAt.END); + itemContentView.setMaxLines(commentDefaultLines); + } else { + itemContentView.setEllipsize(null); + itemContentView.setMaxLines(commentExpandedLines); + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java index e445233c3..42d746eae 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java @@ -59,7 +59,7 @@ public final class ExtractorHelper { } private static void checkServiceId(int serviceId) { - if(serviceId == Constants.NO_SERVICE_ID) { + if (serviceId == Constants.NO_SERVICE_ID) { throw new IllegalArgumentException("serviceId is NO_SERVICE_ID"); } } @@ -122,8 +122,8 @@ public final class ExtractorHelper { } public static Single getMoreChannelItems(final int serviceId, - final String url, - final String nextStreamsUrl) { + final String url, + final String nextStreamsUrl) { checkServiceId(serviceId); return Single.fromCallable(() -> ChannelInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl)); @@ -138,8 +138,8 @@ public final class ExtractorHelper { } public static Single getMorePlaylistItems(final int serviceId, - final String url, - final String nextStreamsUrl) { + final String url, + final String nextStreamsUrl) { checkServiceId(serviceId); return Single.fromCallable(() -> PlaylistInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl)); @@ -154,9 +154,9 @@ public final class ExtractorHelper { } public static Single getMoreKioskItems(final int serviceId, - final String url, - final String nextStreamsUrl, - final String contentCountry) { + final String url, + final String nextStreamsUrl, + final String contentCountry) { return Single.fromCallable(() -> KioskInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl, contentCountry)); @@ -198,17 +198,17 @@ public final class ExtractorHelper { public static Maybe loadFromCache(final int serviceId, final String url) { checkServiceId(serviceId); return Maybe.defer(() -> { - //noinspection unchecked - I info = (I) cache.getFromKey(serviceId, url); - if (MainActivity.DEBUG) Log.d(TAG, "loadFromCache() called, info > " + info); + //noinspection unchecked + I info = (I) cache.getFromKey(serviceId, url); + if (MainActivity.DEBUG) Log.d(TAG, "loadFromCache() called, info > " + info); - // Only return info if it's not null (it is cached) - if (info != null) { - return Maybe.just(info); - } + // Only return info if it's not null (it is cached) + if (info != null) { + return Maybe.just(info); + } - return Maybe.empty(); - }); + return Maybe.empty(); + }); } /** diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml index 7c6568b67..185f7d380 100644 --- a/app/src/main/res/layout/fragment_video_detail.xml +++ b/app/src/main/res/layout/fragment_video_detail.xml @@ -1,6 +1,5 @@ - + tools:src="@drawable/dummy_thumbnail" /> + tools:visibility="visible" /> + tools:visibility="visible" /> + tools:visibility="visible" /> @@ -127,7 +126,7 @@ android:textAppearance="?android:attr/textAppearanceLarge" android:textSize="@dimen/video_item_detail_title_text_size" tools:ignore="RtlHardcoded" - tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a ultricies ex. Integer sit amet sodales risus. Duis non mi et urna pretium bibendum. Nunc eleifend est quis ipsum porttitor egestas. Sed facilisis, nisl quis eleifend pellentesque, orci metus egestas dolor, at accumsan eros metus quis libero."/> + tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a ultricies ex. Integer sit amet sodales risus. Duis non mi et urna pretium bibendum. Nunc eleifend est quis ipsum porttitor egestas. Sed facilisis, nisl quis eleifend pellentesque, orci metus egestas dolor, at accumsan eros metus quis libero." /> + tools:ignore="ContentDescription,RtlHardcoded" /> @@ -150,7 +149,7 @@ android:layout_marginTop="@dimen/video_item_detail_error_panel_margin" android:indeterminate="true" android:visibility="gone" - tools:visibility="visible"/> + tools:visibility="visible" /> + tools:visibility="visible" /> + android:padding="6dp"> + tools:ignore="RtlHardcoded" /> + tools:text="Uploader" /> + tools:text="Published on Oct 2, 2009" /> + tools:text="Description Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a ultricies ex. Integer sit amet sodales risus. Duis non mi et urna pretium bibendum." /> + android:background="?attr/separator_color" /> - - - - + - - - + android:orientation="vertical"> + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/list_comments_item.xml b/app/src/main/res/layout/list_comments_item.xml new file mode 100644 index 000000000..16b6107c5 --- /dev/null +++ b/app/src/main/res/layout/list_comments_item.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/list_comments_mini_item.xml b/app/src/main/res/layout/list_comments_mini_item.xml new file mode 100644 index 000000000..7e8ce1a87 --- /dev/null +++ b/app/src/main/res/layout/list_comments_mini_item.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 9b39fec26..b110a6aa3 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -135,6 +135,7 @@ show_search_suggestions show_play_with_kodi show_next_video + show_comments show_hold_to_append en GB diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0dc837ae8..64ff4ec74 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -129,6 +129,7 @@ Playlist Playlists Videos + Comments Tracks Users Yes From 219922cd8240b00c9efe4feeb4c462f8f0e79211 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Wed, 19 Sep 2018 05:13:55 +0530 Subject: [PATCH 02/37] added commentsInfo in streamInfo --- app/build.gradle | 2 +- .../fragments/detail/VideoDetailFragment.java | 22 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d409532bb..b9e3ce812 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,7 +55,7 @@ dependencies { exclude module: 'support-annotations' } - implementation 'com.github.yausername:NewPipeExtractor:5242bda' + implementation 'com.github.yausername:NewPipeExtractor:4794e16' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.8.9' 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 cbea6803e..90056c724 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 @@ -54,6 +54,7 @@ import org.schabi.newpipe.ReCaptchaActivity; import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.comments.CommentsInfo; import org.schabi.newpipe.extractor.comments.CommentsInfoItem; import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; import org.schabi.newpipe.extractor.exceptions.ParsingException; @@ -252,7 +253,7 @@ public class VideoDetailFragment if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) initRelatedVideos(currentInfo); if ((updateFlags & RESOLUTIONS_MENU_UPDATE_FLAG) != 0) setupActionBar(currentInfo); - if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) initComments(currentInfo); + if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) initComments(currentInfo.getCommentsInfo()); } if ((updateFlags & TOOLBAR_ITEMS_UPDATE_FLAG) != 0 @@ -343,8 +344,7 @@ public class VideoDetailFragment } if (!isLoading.get() && currentInfo != null && isVisible()) { - //TODO fix this. it should not be commented - //outState.putSerializable(INFO_KEY, currentInfo); + outState.putSerializable(INFO_KEY, currentInfo); } outState.putSerializable(STACK_KEY, stack); @@ -425,7 +425,7 @@ public class VideoDetailFragment toggleExpandRelatedVideos(currentInfo); break; case R.id.detail_comments_expand: - toggleExpandComments(currentInfo); + toggleExpandComments(currentInfo.getCommentsInfo()); break; } } @@ -488,9 +488,9 @@ public class VideoDetailFragment } - private void toggleExpandComments(StreamInfo info) { + private void toggleExpandComments(CommentsInfo info) { if (DEBUG) Log.d(TAG, "toggleExpandComments() called with: info = [" + info + "]"); - if (!showComments) return; + if (!showComments || null == info) return; int initialCount = INITIAL_COMMENTS; @@ -519,11 +519,11 @@ public class VideoDetailFragment } } - private void loadMoreComments(StreamInfo info) { + private void loadMoreComments(CommentsInfo info) { if (commentsDisposable != null) commentsDisposable.dispose(); commentsDisposable = Single.fromCallable(() -> { - StreamInfo.loadMoreComments(info); + CommentsInfo.loadMoreComments(info); return info.getComments(); }).subscribeOn(Schedulers.io()).doOnError(e -> info.addError(e)).subscribe(); } @@ -756,10 +756,10 @@ public class VideoDetailFragment } } - private void initComments(StreamInfo info) { + private void initComments(CommentsInfo info) { if (commentsView.getChildCount() > 0) commentsView.removeAllViews(); - if (info.getComments() != null + if (null != info && info.getComments() != null && !info.getComments().isEmpty() && showComments) { //long first = System.nanoTime(), each; int to = info.getComments().size() >= INITIAL_RELATED_VIDEOS @@ -1360,7 +1360,7 @@ public class VideoDetailFragment setupActionBar(info); initThumbnailViews(info); initRelatedVideos(info); - initComments(info); + initComments(info.getCommentsInfo()); if (wasRelatedStreamsExpanded) { toggleExpandRelatedVideos(currentInfo); From 5cc73555cddb81172464663f253e9f2f6cb321a7 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Wed, 19 Sep 2018 05:41:01 +0530 Subject: [PATCH 03/37] updated extractor version --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index b9e3ce812..c4a54f386 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,7 +55,7 @@ dependencies { exclude module: 'support-annotations' } - implementation 'com.github.yausername:NewPipeExtractor:4794e16' + implementation 'com.github.yausername:NewPipeExtractor:e04787f' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.8.9' From 7047b62442320a64a164fd3392e36c5e828e8b85 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Sun, 23 Sep 2018 07:02:19 +0530 Subject: [PATCH 04/37] added comments fragment --- app/build.gradle | 2 +- .../fragments/detail/VideoDetailFragment.java | 173 ++++++++++----- .../list/comments/CommentsFragment.java | 201 ++++++++++++++++++ .../newpipe/info_list/InfoListAdapter.java | 13 +- .../org/schabi/newpipe/report/UserAction.java | 1 + .../schabi/newpipe/util/ExtractorHelper.java | 37 +++- .../org/schabi/newpipe/util/InfoCache.java | 17 +- .../schabi/newpipe/util/NavigationHelper.java | 13 ++ app/src/main/res/layout/fragment_comments.xml | 70 ++++++ .../main/res/layout/fragment_video_detail.xml | 1 + 10 files changed, 451 insertions(+), 77 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java create mode 100644 app/src/main/res/layout/fragment_comments.xml diff --git a/app/build.gradle b/app/build.gradle index c4a54f386..e4c1f24c1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,7 +55,7 @@ dependencies { exclude module: 'support-annotations' } - implementation 'com.github.yausername:NewPipeExtractor:e04787f' + implementation 'com.github.yausername:NewPipeExtractor:c1199c8' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.8.9' 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 90056c724..4357753b4 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 @@ -54,9 +54,12 @@ import org.schabi.newpipe.ReCaptchaActivity; import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.ServiceList; +import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.comments.CommentsInfo; import org.schabi.newpipe.extractor.comments.CommentsInfoItem; import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; import org.schabi.newpipe.extractor.stream.AudioStream; @@ -131,6 +134,7 @@ public class VideoDetailFragment private boolean autoPlayEnabled; private boolean showRelatedStreams; private boolean showComments; + private boolean isCommentsSupported; private boolean wasRelatedStreamsExpanded = false; @State @@ -141,6 +145,7 @@ public class VideoDetailFragment protected String url; private StreamInfo currentInfo; + private CommentsInfo commentsInfo; private Disposable currentWorker; @NonNull private CompositeDisposable disposables = new CompositeDisposable(); @@ -242,6 +247,7 @@ public class VideoDetailFragment public void onPause() { super.onPause(); if (currentWorker != null) currentWorker.dispose(); + if (commentsDisposable != null) commentsDisposable.dispose(); } @Override @@ -253,7 +259,7 @@ public class VideoDetailFragment if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) initRelatedVideos(currentInfo); if ((updateFlags & RESOLUTIONS_MENU_UPDATE_FLAG) != 0) setupActionBar(currentInfo); - if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) initComments(currentInfo.getCommentsInfo()); + if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) initComments(commentsInfo); } if ((updateFlags & TOOLBAR_ITEMS_UPDATE_FLAG) != 0 @@ -267,6 +273,8 @@ public class VideoDetailFragment // Check if it was loading when the fragment was stopped/paused, if (wasLoading.getAndSet(false)) { selectAndLoadVideo(serviceId, url, name); + }else{ + loadComments(false); } } @@ -277,8 +285,10 @@ public class VideoDetailFragment .unregisterOnSharedPreferenceChangeListener(this); if (currentWorker != null) currentWorker.dispose(); + if (commentsDisposable != null) commentsDisposable.dispose(); if (disposables != null) disposables.clear(); currentWorker = null; + commentsDisposable = null; disposables = null; } @@ -359,7 +369,7 @@ public class VideoDetailFragment if (serializable instanceof StreamInfo) { //noinspection unchecked currentInfo = (StreamInfo) serializable; - InfoCache.getInstance().putInfo(serviceId, url, currentInfo); + InfoCache.getInstance().putInfo(serviceId, url, currentInfo, InfoItem.InfoType.STREAM); } serializable = savedState.getSerializable(STACK_KEY); @@ -367,6 +377,7 @@ public class VideoDetailFragment //noinspection unchecked stack.addAll((Collection) serializable); } + } /*////////////////////////////////////////////////////////////////////////// @@ -425,7 +436,7 @@ public class VideoDetailFragment toggleExpandRelatedVideos(currentInfo); break; case R.id.detail_comments_expand: - toggleExpandComments(currentInfo.getCommentsInfo()); + toggleExpandComments(commentsInfo); break; } } @@ -493,40 +504,33 @@ public class VideoDetailFragment if (!showComments || null == info) return; int initialCount = INITIAL_COMMENTS; + int currentCount = commentsView.getChildCount(); - if (commentsView.getChildCount() > initialCount && commentsView.getChildCount() >= info.getComments().size() && !info.hasMoreComments()) { + //collapse + if (currentCount > initialCount && !info.hasNextPage()) { commentsView.removeViews(initialCount, - commentsView.getChildCount() - (initialCount)); + currentCount - (initialCount)); commentsExpandButton.setImageDrawable(ContextCompat.getDrawable( activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand))); return; } - //Log.d(TAG, "toggleExpandRelatedVideos() called with: info = [" + info + "], from = [" + INITIAL_RELATED_VIDEOS + "]"); - int currentCount = commentsView.getChildCount(); - for (int i = currentCount; i < info.getComments().size(); i++) { - CommentsInfoItem item = info.getComments().get(i); - //Log.d(TAG, "i = " + i); - commentsView.addView(infoItemBuilder.buildView(commentsView, item)); - } - - if (info.hasMoreComments()) { - loadMoreComments(info); - } else { - commentsExpandButton.setImageDrawable( - ContextCompat.getDrawable(activity, - ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.collapse))); + if(currentCount < info.getRelatedItems().size()){ + //expand + for (int i = currentCount; i < info.getRelatedItems().size(); i++) { + CommentsInfoItem item = info.getRelatedItems().get(i); + commentsView.addView(infoItemBuilder.buildView(commentsView, item)); + } + if(!info.hasNextPage()){ + commentsExpandButton.setImageDrawable( + ContextCompat.getDrawable(activity, + ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.collapse))); + } + }else{ + NavigationHelper.openCommentsFragment(getFragmentManager(), serviceId, url, name); } } - private void loadMoreComments(CommentsInfo info) { - if (commentsDisposable != null) commentsDisposable.dispose(); - - commentsDisposable = Single.fromCallable(() -> { - CommentsInfo.loadMoreComments(info); - return info.getComments(); - }).subscribeOn(Schedulers.io()).doOnError(e -> info.addError(e)).subscribe(); - } /*////////////////////////////////////////////////////////////////////////// // Init //////////////////////////////////////////////////////////////////////////*/ @@ -573,23 +577,17 @@ public class VideoDetailFragment uploaderTextView = rootView.findViewById(R.id.detail_uploader_text_view); uploaderThumb = rootView.findViewById(R.id.detail_uploader_thumbnail_view); - tabHost = (TabHost) rootView.findViewById(R.id.tab_host); - tabHost.setup(); + StreamingService service = null; + try { + service = NewPipe.getService(serviceId); + } catch (ExtractionException e) { + onError(e); + } - TabHost.TabSpec commentsTab = tabHost.newTabSpec(COMMENTS_TAB_TAG); - commentsTab.setContent(R.id.detail_comments_root_layout); - commentsTab.setIndicator(getString(R.string.comments)); - - - TabHost.TabSpec relatedVideosTab = tabHost.newTabSpec(RELATED_TAB_TAG); - relatedVideosTab.setContent(R.id.detail_related_streams_root_layout); - relatedVideosTab.setIndicator(getString(R.string.next_video_title)); - - tabHost.addTab(commentsTab); - tabHost.addTab(relatedVideosTab); - - //show comments tab by default - tabHost.setCurrentTabByTag(COMMENTS_TAB_TAG); + if (service.isCommentsSupported()) { + isCommentsSupported = true; + initTabs(rootView); + } relatedStreamRootLayout = rootView.findViewById(R.id.detail_related_streams_root_layout); nextStreamTitle = rootView.findViewById(R.id.detail_next_stream_title); @@ -606,6 +604,25 @@ public class VideoDetailFragment } + private void initTabs(View rootView) { + tabHost = (TabHost) rootView.findViewById(R.id.tab_host); + tabHost.setup(); + + TabHost.TabSpec commentsTab = tabHost.newTabSpec(COMMENTS_TAB_TAG); + commentsTab.setContent(R.id.detail_comments_root_layout); + commentsTab.setIndicator(getString(R.string.comments)); + + TabHost.TabSpec relatedVideosTab = tabHost.newTabSpec(RELATED_TAB_TAG); + relatedVideosTab.setContent(R.id.detail_related_streams_root_layout); + relatedVideosTab.setIndicator(getString(R.string.next_video_title)); + + tabHost.addTab(commentsTab); + tabHost.addTab(relatedVideosTab); + + //show comments tab by default + tabHost.setCurrentTabByTag(COMMENTS_TAB_TAG); + } + @Override protected void initListeners() { super.initListeners(); @@ -751,22 +768,25 @@ public class VideoDetailFragment } private void showRelatedStreamsIfSelected() { - if (tabHost.getCurrentTabTag().contentEquals(RELATED_TAB_TAG)) { + if (null == tabHost || tabHost.getCurrentTabTag().contentEquals(RELATED_TAB_TAG)) { relatedStreamRootLayout.setVisibility(View.VISIBLE); } } private void initComments(CommentsInfo info) { + if(null == info) return; + if (commentsView.getChildCount() > 0) commentsView.removeAllViews(); - if (null != info && info.getComments() != null - && !info.getComments().isEmpty() && showComments) { + List initialComments = info.getRelatedItems(); + if (null != info && initialComments != null + && !initialComments.isEmpty() && showComments) { //long first = System.nanoTime(), each; - int to = info.getComments().size() >= INITIAL_RELATED_VIDEOS - ? INITIAL_RELATED_VIDEOS - : info.getComments().size(); + int to = initialComments.size() >= INITIAL_COMMENTS + ? INITIAL_COMMENTS + : initialComments.size(); for (int i = 0; i < to; i++) { - InfoItem item = info.getComments().get(i); + InfoItem item = initialComments.get(i); //each = System.nanoTime(); commentsView.addView(infoItemBuilder.buildView(commentsView, item)); //if (DEBUG) Log.d(TAG, "each took " + ((System.nanoTime() - each) / 1000000L) + "ms"); @@ -774,10 +794,13 @@ public class VideoDetailFragment //if (DEBUG) Log.d(TAG, "Total time " + ((System.nanoTime() - first) / 1000000L) + "ms"); showCommentsIfSelected(); - commentsExpandButton.setVisibility(View.VISIBLE); - - commentsExpandButton.setImageDrawable(ContextCompat.getDrawable( - activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand))); + if(initialComments.size() > INITIAL_COMMENTS){ + commentsExpandButton.setVisibility(View.VISIBLE); + commentsExpandButton.setImageDrawable(ContextCompat.getDrawable( + activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand))); + }else{ + commentsExpandButton.setVisibility(View.GONE); + } } else { commentsRootLayout.setVisibility(View.GONE); } @@ -785,11 +808,16 @@ public class VideoDetailFragment } private void showCommentsIfSelected() { - if (tabHost.getCurrentTabTag().contentEquals(COMMENTS_TAB_TAG)) { + if (null == tabHost || tabHost.getCurrentTabTag().contentEquals(COMMENTS_TAB_TAG)) { commentsRootLayout.setVisibility(View.VISIBLE); } } + private void clearComments(){ + if (commentsView.getChildCount() > 0) commentsView.removeAllViews(); + commentsExpandButton.setVisibility(View.GONE); + } + /*////////////////////////////////////////////////////////////////////////// // Menu //////////////////////////////////////////////////////////////////////////*/ @@ -988,6 +1016,7 @@ public class VideoDetailFragment protected void prepareAndLoadInfo() { parallaxScrollRootView.smoothScrollTo(0, 0); pushToStack(serviceId, url, name); + //clearComments(); startLoading(false); } @@ -1010,6 +1039,27 @@ public class VideoDetailFragment isLoading.set(false); onError(throwable); }); + + loadComments(forceLoad); + + } + + private void loadComments(boolean forceLoad) { + if(isCommentsSupported && showComments){ + commentsInfo = null; + if (commentsDisposable != null) commentsDisposable.dispose(); + + commentsDisposable = ExtractorHelper.getCommentsInfo(serviceId, url, forceLoad) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((@NonNull CommentsInfo result) -> { + commentsInfo = result; + showCommentsWithAnimation(120, 0,0); + initComments(commentsInfo); + }, (@NonNull Throwable throwable) -> { + onError(throwable); + }); + } } /*////////////////////////////////////////////////////////////////////////// @@ -1199,7 +1249,7 @@ public class VideoDetailFragment .setInterpolator(new FastOutSlowInInterpolator()) .start(); - if (showRelatedStreams && tabHost.getCurrentTabTag().contentEquals(RELATED_TAB_TAG)) { + if (showRelatedStreams && (null == tabHost || tabHost.getCurrentTabTag().contentEquals(RELATED_TAB_TAG))) { relatedStreamRootLayout.animate().setListener(null).cancel(); relatedStreamRootLayout.setAlpha(0f); relatedStreamRootLayout.setTranslationY(translationY); @@ -1213,7 +1263,15 @@ public class VideoDetailFragment .start(); } - if (showComments && tabHost.getCurrentTabTag().contentEquals(COMMENTS_TAB_TAG)) { + } + + private void showCommentsWithAnimation(long duration, + long delay, + @FloatRange(from = 0.0f, to = 1.0f) float translationPercent) { + int translationY = (int) (getResources().getDisplayMetrics().heightPixels * + (translationPercent > 0.0f ? translationPercent : .06f)); + + if (showComments && (null == tabHost || tabHost.getCurrentTabTag().contentEquals(COMMENTS_TAB_TAG))) { commentsRootLayout.animate().setListener(null).cancel(); commentsRootLayout.setAlpha(0f); commentsRootLayout.setTranslationY(translationY); @@ -1360,7 +1418,6 @@ public class VideoDetailFragment setupActionBar(info); initThumbnailViews(info); initRelatedVideos(info); - initComments(info.getCommentsInfo()); if (wasRelatedStreamsExpanded) { toggleExpandRelatedVideos(currentInfo); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java new file mode 100644 index 000000000..78787107a --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java @@ -0,0 +1,201 @@ +package org.schabi.newpipe.fragments.list.comments; + +import android.app.Activity; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.ActionBar; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.jakewharton.rxbinding2.view.RxView; + +import org.schabi.newpipe.R; +import org.schabi.newpipe.database.subscription.SubscriptionEntity; +import org.schabi.newpipe.extractor.InfoItem; +import org.schabi.newpipe.extractor.ListExtractor; +import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.channel.ChannelInfo; +import org.schabi.newpipe.extractor.comments.CommentsInfo; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.stream.StreamInfoItem; +import org.schabi.newpipe.fragments.list.BaseListInfoFragment; +import org.schabi.newpipe.info_list.InfoItemDialog; +import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; +import org.schabi.newpipe.local.subscription.SubscriptionService; +import org.schabi.newpipe.player.playqueue.ChannelPlayQueue; +import org.schabi.newpipe.player.playqueue.PlayQueue; +import org.schabi.newpipe.player.playqueue.SinglePlayQueue; +import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.util.AnimationUtils; +import org.schabi.newpipe.util.ExtractorHelper; +import org.schabi.newpipe.util.ImageDisplayConstants; +import org.schabi.newpipe.util.Localization; +import org.schabi.newpipe.util.NavigationHelper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import io.reactivex.Observable; +import io.reactivex.Single; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; +import io.reactivex.functions.Action; +import io.reactivex.functions.Consumer; +import io.reactivex.functions.Function; +import io.reactivex.schedulers.Schedulers; + +import static org.schabi.newpipe.util.AnimationUtils.animateBackgroundColor; +import static org.schabi.newpipe.util.AnimationUtils.animateTextColor; +import static org.schabi.newpipe.util.AnimationUtils.animateView; + +public class CommentsFragment extends BaseListInfoFragment { + + private CompositeDisposable disposables = new CompositeDisposable(); + + /*////////////////////////////////////////////////////////////////////////// + // Views + //////////////////////////////////////////////////////////////////////////*/ + + + + private boolean mIsVisibleToUser = false; + + public static CommentsFragment getInstance(int serviceId, String url, String name) { + CommentsFragment instance = new CommentsFragment(); + instance.setInitialData(serviceId, url, name); + return instance; + } + + /*////////////////////////////////////////////////////////////////////////// + // LifeCycle + //////////////////////////////////////////////////////////////////////////*/ + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + mIsVisibleToUser = isVisibleToUser; + if(activity != null + && useAsFrontPage + && isVisibleToUser) { + setTitle(currentInfo != null ? currentInfo.getName() : name); + } + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_comments, container, false); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (disposables != null) disposables.clear(); + } + + /*////////////////////////////////////////////////////////////////////////// + // Init + //////////////////////////////////////////////////////////////////////////*/ + + + /*////////////////////////////////////////////////////////////////////////// + // Menu + //////////////////////////////////////////////////////////////////////////*/ + + + /*////////////////////////////////////////////////////////////////////////// + // Load and handle + //////////////////////////////////////////////////////////////////////////*/ + + @Override + protected Single loadMoreItemsLogic() { + return ExtractorHelper.getMoreCommentItems(serviceId, currentInfo, currentNextPageUrl); + } + + @Override + protected Single loadResult(boolean forceLoad) { + return ExtractorHelper.getCommentsInfo(serviceId, url, forceLoad); + } + + /*////////////////////////////////////////////////////////////////////////// + // Contract + //////////////////////////////////////////////////////////////////////////*/ + + @Override + public void showLoading() { + super.showLoading(); + } + + @Override + public void handleResult(@NonNull CommentsInfo result) { + super.handleResult(result); + + if (!result.getErrors().isEmpty()) { + showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); + } + + if (disposables != null) disposables.clear(); + } + + @Override + public void handleNextItems(ListExtractor.InfoItemsPage result) { + super.handleNextItems(result); + + if (!result.getErrors().isEmpty()) { + showSnackBarError(result.getErrors(), + UserAction.REQUESTED_COMMENTS, + NewPipe.getNameOfService(serviceId), + "Get next page of: " + url, + R.string.general_error); + } + } + + /*////////////////////////////////////////////////////////////////////////// + // OnError + //////////////////////////////////////////////////////////////////////////*/ + + @Override + protected boolean onError(Throwable exception) { + if (super.onError(exception)) return true; + + int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error; + onUnrecoverableError(exception, + UserAction.REQUESTED_COMMENTS, + NewPipe.getNameOfService(serviceId), + url, + errorId); + return true; + } + + /*////////////////////////////////////////////////////////////////////////// + // Utils + //////////////////////////////////////////////////////////////////////////*/ + + @Override + public void setTitle(String title) { + super.setTitle(title); + } +} diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java index 49bd2bdf1..64abf67f8 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java @@ -13,6 +13,8 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder; import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder; +import org.schabi.newpipe.info_list.holder.CommentsInfoItemHolder; +import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder; import org.schabi.newpipe.info_list.holder.InfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder; @@ -57,6 +59,8 @@ public class InfoListAdapter extends RecyclerView.Adapter infoItemList; @@ -216,6 +220,8 @@ public class InfoListAdapter extends RecyclerView.Adapter + return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.STREAM, Single.fromCallable(() -> StreamInfo.getInfo(NewPipe.getService(serviceId), url))); } @@ -117,7 +119,7 @@ public final class ExtractorHelper { final String url, boolean forceLoad) { checkServiceId(serviceId); - return checkCache(forceLoad, serviceId, url, Single.fromCallable(() -> + return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.CHANNEL, Single.fromCallable(() -> ChannelInfo.getInfo(NewPipe.getService(serviceId), url))); } @@ -129,11 +131,27 @@ public final class ExtractorHelper { ChannelInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl)); } + public static Single getCommentsInfo(final int serviceId, + final String url, + boolean forceLoad) { + checkServiceId(serviceId); + return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.COMMENT, Single.fromCallable(() -> + CommentsInfo.getInfo(NewPipe.getService(serviceId), url))); + } + + public static Single getMoreCommentItems(final int serviceId, + final CommentsInfo info, + final String nextPageUrl) { + checkServiceId(serviceId); + return Single.fromCallable(() -> + CommentsInfo.getMoreItems(NewPipe.getService(serviceId), info, nextPageUrl)); + } + public static Single getPlaylistInfo(final int serviceId, final String url, boolean forceLoad) { checkServiceId(serviceId); - return checkCache(forceLoad, serviceId, url, Single.fromCallable(() -> + return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.PLAYLIST, Single.fromCallable(() -> PlaylistInfo.getInfo(NewPipe.getService(serviceId), url))); } @@ -149,7 +167,7 @@ public final class ExtractorHelper { final String url, final String contentCountry, boolean forceLoad) { - return checkCache(forceLoad, serviceId, url, Single.fromCallable(() -> + return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.PLAYLIST, Single.fromCallable(() -> KioskInfo.getInfo(NewPipe.getService(serviceId), url, contentCountry))); } @@ -174,16 +192,17 @@ public final class ExtractorHelper { private static Single checkCache(boolean forceLoad, int serviceId, String url, + InfoItem.InfoType infoType, Single loadFromNetwork) { checkServiceId(serviceId); - loadFromNetwork = loadFromNetwork.doOnSuccess(info -> cache.putInfo(serviceId, url, info)); + loadFromNetwork = loadFromNetwork.doOnSuccess(info -> cache.putInfo(serviceId, url, info, infoType)); Single load; if (forceLoad) { - cache.removeInfo(serviceId, url); + cache.removeInfo(serviceId, url, infoType); load = loadFromNetwork; } else { - load = Maybe.concat(ExtractorHelper.loadFromCache(serviceId, url), + load = Maybe.concat(ExtractorHelper.loadFromCache(serviceId, url, infoType), loadFromNetwork.toMaybe()) .firstElement() //Take the first valid .toSingle(); @@ -195,11 +214,11 @@ public final class ExtractorHelper { /** * Default implementation uses the {@link InfoCache} to get cached results */ - public static Maybe loadFromCache(final int serviceId, final String url) { + public static Maybe loadFromCache(final int serviceId, final String url, InfoItem.InfoType infoType) { checkServiceId(serviceId); return Maybe.defer(() -> { //noinspection unchecked - I info = (I) cache.getFromKey(serviceId, url); + I info = (I) cache.getFromKey(serviceId, url, infoType); if (MainActivity.DEBUG) Log.d(TAG, "loadFromCache() called, info > " + info); // Only return info if it's not null (it is cached) 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 ecc66bb40..82f64a5ff 100644 --- a/app/src/main/java/org/schabi/newpipe/util/InfoCache.java +++ b/app/src/main/java/org/schabi/newpipe/util/InfoCache.java @@ -26,6 +26,7 @@ import android.util.Log; import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.extractor.Info; +import org.schabi.newpipe.extractor.InfoItem; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -55,27 +56,27 @@ public final class InfoCache { } @Nullable - public Info getFromKey(int serviceId, @NonNull String url) { + public Info getFromKey(int serviceId, @NonNull String url, @NonNull InfoItem.InfoType infoType) { if (DEBUG) Log.d(TAG, "getFromKey() called with: serviceId = [" + serviceId + "], url = [" + url + "]"); synchronized (lruCache) { - return getInfo(lruCache, keyOf(serviceId, url)); + return getInfo(lruCache, keyOf(serviceId, url, infoType)); } } - public void putInfo(int serviceId, @NonNull String url, @NonNull Info info) { + public void putInfo(int serviceId, @NonNull String url, @NonNull Info info, @NonNull InfoItem.InfoType infoType) { if (DEBUG) Log.d(TAG, "putInfo() called with: info = [" + info + "]"); final long expirationMillis = ServiceHelper.getCacheExpirationMillis(info.getServiceId()); synchronized (lruCache) { final CacheData data = new CacheData(info, expirationMillis); - lruCache.put(keyOf(serviceId, url), data); + lruCache.put(keyOf(serviceId, url, infoType), data); } } - public void removeInfo(int serviceId, @NonNull String url) { + public void removeInfo(int serviceId, @NonNull String url, @NonNull InfoItem.InfoType infoType) { if (DEBUG) Log.d(TAG, "removeInfo() called with: serviceId = [" + serviceId + "], url = [" + url + "]"); synchronized (lruCache) { - lruCache.remove(keyOf(serviceId, url)); + lruCache.remove(keyOf(serviceId, url, infoType)); } } @@ -101,8 +102,8 @@ public final class InfoCache { } @NonNull - private static String keyOf(final int serviceId, @NonNull final String url) { - return serviceId + url; + private static String keyOf(final int serviceId, @NonNull final String url, @NonNull InfoItem.InfoType infoType) { + return serviceId + url + infoType.toString(); } private static void removeStaleCache(@NonNull final LruCache cache) { diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index 13767125d..27cf7bf71 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -34,6 +34,7 @@ import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.fragments.MainFragment; import org.schabi.newpipe.fragments.detail.VideoDetailFragment; import org.schabi.newpipe.fragments.list.channel.ChannelFragment; +import org.schabi.newpipe.fragments.list.comments.CommentsFragment; import org.schabi.newpipe.local.bookmark.BookmarkFragment; import org.schabi.newpipe.local.feed.FeedFragment; import org.schabi.newpipe.fragments.list.kiosk.KioskFragment; @@ -331,6 +332,18 @@ public class NavigationHelper { .commit(); } + public static void openCommentsFragment( + FragmentManager fragmentManager, + int serviceId, + String url, + String name) { + if (name == null) name = ""; + defaultTransaction(fragmentManager) + .replace(R.id.fragment_holder, CommentsFragment.getInstance(serviceId, url, name)) + .addToBackStack(null) + .commit(); + } + public static void openPlaylistFragment(FragmentManager fragmentManager, int serviceId, String url, diff --git a/app/src/main/res/layout/fragment_comments.xml b/app/src/main/res/layout/fragment_comments.xml new file mode 100644 index 000000000..97ad5c247 --- /dev/null +++ b/app/src/main/res/layout/fragment_comments.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml index 185f7d380..c59c4ac11 100644 --- a/app/src/main/res/layout/fragment_video_detail.xml +++ b/app/src/main/res/layout/fragment_video_detail.xml @@ -495,6 +495,7 @@ android:src="?attr/expand" android:textAlignment="center" android:textAllCaps="true" + android:visibility="gone" tools:ignore="ContentDescription" /> From 66c753f3a3845346249b4ef5a92e891b01ffd094 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Sun, 23 Sep 2018 15:22:45 +0530 Subject: [PATCH 05/37] changed comments fragment loading animation --- .../newpipe/fragments/list/comments/CommentsFragment.java | 6 +++++- .../main/java/org/schabi/newpipe/util/NavigationHelper.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java index 78787107a..3e9cfe44c 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java @@ -70,7 +70,7 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView; public class CommentsFragment extends BaseListInfoFragment { private CompositeDisposable disposables = new CompositeDisposable(); - + private boolean initialLoad = true; /*////////////////////////////////////////////////////////////////////////// // Views //////////////////////////////////////////////////////////////////////////*/ @@ -152,6 +152,10 @@ public class CommentsFragment extends BaseListInfoFragment { @Override public void handleResult(@NonNull CommentsInfo result) { super.handleResult(result); + if(initialLoad){ + itemsList.smoothScrollToPosition(infoListAdapter.getItemCount()); + initialLoad = false; + } if (!result.getErrors().isEmpty()) { showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index 27cf7bf71..77bcec10b 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -338,7 +338,7 @@ public class NavigationHelper { String url, String name) { if (name == null) name = ""; - defaultTransaction(fragmentManager) + fragmentManager.beginTransaction().setCustomAnimations(R.anim.switch_service_in, R.anim.switch_service_out) .replace(R.id.fragment_holder, CommentsFragment.getInstance(serviceId, url, name)) .addToBackStack(null) .commit(); From d694c5f511461a6fa939cb2ffe5c83777d39cafe Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Sun, 23 Sep 2018 19:45:26 +0530 Subject: [PATCH 06/37] smoother transition to comments fragment --- .../fragments/detail/VideoDetailFragment.java | 28 ++----------------- .../list/comments/CommentsFragment.java | 3 +- 2 files changed, 4 insertions(+), 27 deletions(-) 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 4357753b4..64d785bcb 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 @@ -121,7 +121,7 @@ public class VideoDetailFragment // Amount of videos to show on start private static final int INITIAL_RELATED_VIDEOS = 8; // Amount of comments to show on start - private static final int INITIAL_COMMENTS = 8; + public static final int INITIAL_COMMENTS = 8; private InfoItemBuilder infoItemBuilder = null; @@ -503,32 +503,8 @@ public class VideoDetailFragment if (DEBUG) Log.d(TAG, "toggleExpandComments() called with: info = [" + info + "]"); if (!showComments || null == info) return; - int initialCount = INITIAL_COMMENTS; - int currentCount = commentsView.getChildCount(); + NavigationHelper.openCommentsFragment(getFragmentManager(), serviceId, url, name); - //collapse - if (currentCount > initialCount && !info.hasNextPage()) { - commentsView.removeViews(initialCount, - currentCount - (initialCount)); - commentsExpandButton.setImageDrawable(ContextCompat.getDrawable( - activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand))); - return; - } - - if(currentCount < info.getRelatedItems().size()){ - //expand - for (int i = currentCount; i < info.getRelatedItems().size(); i++) { - CommentsInfoItem item = info.getRelatedItems().get(i); - commentsView.addView(infoItemBuilder.buildView(commentsView, item)); - } - if(!info.hasNextPage()){ - commentsExpandButton.setImageDrawable( - ContextCompat.getDrawable(activity, - ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.collapse))); - } - }else{ - NavigationHelper.openCommentsFragment(getFragmentManager(), serviceId, url, name); - } } /*////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java index 3e9cfe44c..02815407a 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java @@ -34,6 +34,7 @@ import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.comments.CommentsInfo; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.stream.StreamInfoItem; +import org.schabi.newpipe.fragments.detail.VideoDetailFragment; import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.info_list.InfoItemDialog; import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; @@ -153,7 +154,7 @@ public class CommentsFragment extends BaseListInfoFragment { public void handleResult(@NonNull CommentsInfo result) { super.handleResult(result); if(initialLoad){ - itemsList.smoothScrollToPosition(infoListAdapter.getItemCount()); + itemsList.smoothScrollToPosition(VideoDetailFragment.INITIAL_COMMENTS); initialLoad = false; } From 515be677a918b45181b9e6bc956de668a3956432 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Mon, 24 Sep 2018 14:53:43 +0530 Subject: [PATCH 07/37] no comments --- .../fragments/detail/VideoDetailFragment.java | 11 +++++-- app/src/main/res/layout/fragment_comments.xml | 2 +- .../main/res/layout/fragment_video_detail.xml | 29 +++++++++++++++++++ app/src/main/res/values/strings.xml | 7 +++++ 4 files changed, 45 insertions(+), 4 deletions(-) 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 64d785bcb..09e9b38d7 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 @@ -54,7 +54,6 @@ import org.schabi.newpipe.ReCaptchaActivity; import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.comments.CommentsInfo; import org.schabi.newpipe.extractor.comments.CommentsInfoItem; @@ -200,6 +199,7 @@ public class VideoDetailFragment private ImageButton relatedStreamExpandButton; private LinearLayout commentsRootLayout; + private View commentsEmptyStateView; private LinearLayout commentsView; private ImageButton commentsExpandButton; private Disposable commentsDisposable; @@ -571,6 +571,7 @@ public class VideoDetailFragment relatedStreamExpandButton = rootView.findViewById(R.id.detail_related_streams_expand); commentsRootLayout = rootView.findViewById(R.id.detail_comments_root_layout); + commentsEmptyStateView = rootView.findViewById(R.id.comments_empty_state_view); commentsView = rootView.findViewById(R.id.detail_comments_view); commentsExpandButton = rootView.findViewById(R.id.detail_comments_expand); @@ -750,9 +751,13 @@ public class VideoDetailFragment } private void initComments(CommentsInfo info) { - if(null == info) return; + clearComments(); - if (commentsView.getChildCount() > 0) commentsView.removeAllViews(); + if(null == info || null == info.getRelatedItems() || info.getRelatedItems().size() == 0){ + commentsEmptyStateView.setVisibility(View.VISIBLE); + return; + } + commentsEmptyStateView.setVisibility(View.GONE); List initialComments = info.getRelatedItems(); if (null != info && initialComments != null diff --git a/app/src/main/res/layout/fragment_comments.xml b/app/src/main/res/layout/fragment_comments.xml index 97ad5c247..83e788070 100644 --- a/app/src/main/res/layout/fragment_comments.xml +++ b/app/src/main/res/layout/fragment_comments.xml @@ -45,7 +45,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:text="@string/empty_view_no_videos" + android:text="@string/empty_view_no_comments" android:textSize="24sp"/> diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml index c59c4ac11..870043eb1 100644 --- a/app/src/main/res/layout/fragment_video_detail.xml +++ b/app/src/main/res/layout/fragment_video_detail.xml @@ -477,6 +477,35 @@ android:layout_marginTop="14dp" android:orientation="vertical"> + + + + + + + + User report No results @string/no_videos + @string/no_comments Nothing Here But Crickets Drag to reorder @@ -264,6 +265,12 @@ %s videos + No comments + + %s comment + %s comments + + Start Pause From a29e2116a7ed127da639d59b5ac97f96c3f259b3 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Thu, 27 Sep 2018 00:53:36 +0530 Subject: [PATCH 08/37] handling error while loading comments --- app/build.gradle | 2 +- .../newpipe/fragments/detail/VideoDetailFragment.java | 8 ++++++-- app/src/main/res/values/strings.xml | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e4c1f24c1..0b264d8c6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,7 +55,7 @@ dependencies { exclude module: 'support-annotations' } - implementation 'com.github.yausername:NewPipeExtractor:c1199c8' + implementation 'com.github.yausername:NewPipeExtractor:fb14196' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.8.9' 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 09e9b38d7..1629afadd 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 @@ -997,7 +997,6 @@ public class VideoDetailFragment protected void prepareAndLoadInfo() { parallaxScrollRootView.smoothScrollTo(0, 0); pushToStack(serviceId, url, name); - //clearComments(); startLoading(false); } @@ -1027,6 +1026,7 @@ public class VideoDetailFragment private void loadComments(boolean forceLoad) { if(isCommentsSupported && showComments){ + clearComments(); commentsInfo = null; if (commentsDisposable != null) commentsDisposable.dispose(); @@ -1038,7 +1038,7 @@ public class VideoDetailFragment showCommentsWithAnimation(120, 0,0); initComments(commentsInfo); }, (@NonNull Throwable throwable) -> { - onError(throwable); + onCommentsError(throwable); }); } } @@ -1495,4 +1495,8 @@ public class VideoDetailFragment showError(getString(R.string.blocked_by_gema), false, R.drawable.gruese_die_gema); } + + public void onCommentsError(Throwable exception) { + showSnackBarError(exception, UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(serviceId), url, R.string.error_unable_to_load_comments); + } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 23039a4c7..3dbbc29cf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -389,6 +389,7 @@ Warning: Could not import all files. This will override your current setup. Do you want to also import settings? + Could not load comments Kiosk From 4e6722f201569df3b01af5347a1c4f1336c814e2 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Thu, 27 Sep 2018 04:20:57 +0530 Subject: [PATCH 09/37] updated extractor and downloader --- app/build.gradle | 2 +- .../java/org/schabi/newpipe/Downloader.java | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 0b264d8c6..0eef1e2d0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,7 +55,7 @@ dependencies { exclude module: 'support-annotations' } - implementation 'com.github.yausername:NewPipeExtractor:fb14196' + implementation 'com.github.yausername:NewPipeExtractor:6b62091' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.8.9' diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index d51d31e11..528141c49 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -3,6 +3,7 @@ package org.schabi.newpipe; import android.support.annotation.Nullable; import android.text.TextUtils; +import org.schabi.newpipe.extractor.DownloadRequest; import org.schabi.newpipe.extractor.DownloadResponse; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; @@ -186,10 +187,11 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader { @Override - public DownloadResponse get(String siteUrl, Map> requestHeaders) throws IOException, ReCaptchaException { + public DownloadResponse get(String siteUrl, DownloadRequest request) throws IOException, ReCaptchaException { final Request.Builder requestBuilder = new Request.Builder() .method("GET", null).url(siteUrl); + Map> requestHeaders = request.getRequestHeaders(); // set custom headers in request for (Map.Entry> pair : requestHeaders.entrySet()) { for(String value : pair.getValue()){ @@ -205,8 +207,8 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader { requestBuilder.addHeader("Cookie", mCookies); } - final Request request = requestBuilder.build(); - final Response response = client.newCall(request).execute(); + final Request okRequest = requestBuilder.build(); + final Response response = client.newCall(okRequest).execute(); final ResponseBody body = response.body(); if (response.code() == 429) { @@ -223,12 +225,13 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader { @Override public DownloadResponse get(String siteUrl) throws IOException, ReCaptchaException { - return get(siteUrl, Collections.emptyMap()); + return get(siteUrl, DownloadRequest.emptyRequest); } @Override - public DownloadResponse post(String siteUrl, String requestBody, Map> requestHeaders) throws IOException, ReCaptchaException { + public DownloadResponse post(String siteUrl, DownloadRequest request) throws IOException, ReCaptchaException { + Map> requestHeaders = request.getRequestHeaders(); if(null == requestHeaders.get("Content-Type") || requestHeaders.get("Content-Type").isEmpty()){ // content type header is required. maybe throw an exception here return null; @@ -236,7 +239,10 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader { String contentType = requestHeaders.get("Content-Type").get(0); - RequestBody okRequestBody = RequestBody.create(MediaType.parse(contentType), requestBody); + RequestBody okRequestBody = null; + if(null != request.getRequestBody()){ + okRequestBody = RequestBody.create(MediaType.parse(contentType), request.getRequestBody()); + } final Request.Builder requestBuilder = new Request.Builder() .method("POST", okRequestBody).url(siteUrl); @@ -255,8 +261,8 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader { requestBuilder.addHeader("Cookie", mCookies); } - final Request request = requestBuilder.build(); - final Response response = client.newCall(request).execute(); + final Request okRequest = requestBuilder.build(); + final Response response = client.newCall(okRequest).execute(); final ResponseBody body = response.body(); if (response.code() == 429) { From 08bbfc50eebc906ddb4cc6642f0944b29feca473 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Thu, 27 Sep 2018 23:27:52 +0530 Subject: [PATCH 10/37] updated extractor --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 0eef1e2d0..e1727665a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,7 +55,7 @@ dependencies { exclude module: 'support-annotations' } - implementation 'com.github.yausername:NewPipeExtractor:6b62091' + implementation 'com.github.yausername:NewPipeExtractor:c2ed99b' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.8.9' From 803b8eab282fe343fb28f03a3019addefcff4515 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Fri, 28 Sep 2018 05:04:36 +0530 Subject: [PATCH 11/37] updated extractor version --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index e1727665a..2104d2023 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,7 +55,7 @@ dependencies { exclude module: 'support-annotations' } - implementation 'com.github.yausername:NewPipeExtractor:c2ed99b' + implementation 'com.github.yausername:NewPipeExtractor:d1ff1c7' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.8.9' From 2e9a860aaa138f9682d363eece897506b823e340 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Tue, 2 Oct 2018 20:39:16 +0530 Subject: [PATCH 12/37] added viewpager. changed from parallaxscrollview to coordinate layout --- .../newpipe/fragments/detail/TabAdaptor.java | 82 +++++ .../fragments/detail/VideoDetailFragment.java | 348 +++--------------- .../list/comments/CommentsFragment.java | 33 +- .../list/videos/RelatedVideosFragment.java | 150 ++++++++ .../newpipe/util/RelatedStreamInfo.java | 23 ++ app/src/main/res/layout/fragment_comments.xml | 2 +- .../res/layout/fragment_related_streams.xml | 70 ++++ .../main/res/layout/fragment_video_detail.xml | 304 +++++---------- 8 files changed, 484 insertions(+), 528 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java create mode 100644 app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java create mode 100644 app/src/main/java/org/schabi/newpipe/util/RelatedStreamInfo.java create mode 100644 app/src/main/res/layout/fragment_related_streams.xml diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java new file mode 100644 index 000000000..c091f45b2 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java @@ -0,0 +1,82 @@ +package org.schabi.newpipe.fragments.detail; + +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.view.PagerAdapter; + +import java.util.ArrayList; +import java.util.List; + +public class TabAdaptor extends FragmentPagerAdapter { + + private final List mFragmentList = new ArrayList<>(); + private final List mFragmentTitleList = new ArrayList<>(); + int baseId = 0; + + public TabAdaptor(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int position) { + return mFragmentList.get(position); + } + + @Override + public int getCount() { + return mFragmentList.size(); + } + + @Nullable + @Override + public CharSequence getPageTitle(int position) { + return mFragmentTitleList.get(position); + } + + @Override + public long getItemId(int position) { + // give an ID different from position when position has been changed + return baseId + position; + } + + public void addFragment(Fragment fragment, String title) { + mFragmentList.add(fragment); + mFragmentTitleList.add(title); + notifyDataSetChanged(); + } + + public void clearAllItems() { + mFragmentList.clear(); + mFragmentTitleList.clear(); + notifyDataSetChanged(); + } + + public void removeItem(int position){ + mFragmentList.remove(position == 0 ? 0 : position - 1); + mFragmentTitleList.remove(position == 0 ? 0 : position - 1); + notifyDataSetChanged(); + } + + public void updateItem(int position, Fragment fragment){ + mFragmentList.set(position, fragment); + // shift the ID returned by getItemId outside the range of all previous fragments + // https://stackoverflow.com/questions/10396321/remove-fragment-page-from-viewpager-in-android + baseId += getCount() + 1; + notifyDataSetChanged(); + } + + public void updateItem(String title, Fragment fragment){ + int index = mFragmentTitleList.indexOf(title); + if(index != -1){ + updateItem(index, fragment); + } + } + + @Override + public int getItemPosition(Object object) { + if (mFragmentList.contains(object)) return mFragmentList.indexOf(object); + else return POSITION_NONE; + } +} 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 6a3e31fc1..ded6be349 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 @@ -13,7 +13,11 @@ import android.support.annotation.DrawableRes; import android.support.annotation.FloatRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.TabLayout; +import android.support.v4.app.Fragment; import android.support.v4.content.ContextCompat; +import android.support.v4.view.ViewPager; import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.support.v7.app.ActionBar; import android.support.v7.app.AlertDialog; @@ -40,11 +44,9 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.Spinner; -import android.widget.TabHost; import android.widget.TextView; import android.widget.Toast; -import com.nirhart.parallaxscroll.views.ParallaxScrollView; import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; @@ -56,7 +58,6 @@ import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.comments.CommentsInfo; -import org.schabi.newpipe.extractor.comments.CommentsInfoItem; import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ParsingException; @@ -69,6 +70,8 @@ import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.fragments.BackPressable; import org.schabi.newpipe.fragments.BaseStateFragment; +import org.schabi.newpipe.fragments.list.comments.CommentsFragment; +import org.schabi.newpipe.fragments.list.videos.RelatedVideosFragment; import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemDialog; import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; @@ -117,13 +120,6 @@ public class VideoDetailFragment View.OnLongClickListener { public static final String AUTO_PLAY = "auto_play"; - // Amount of videos to show on start - private static final int INITIAL_RELATED_VIDEOS = 8; - // Amount of comments to show on start - public static final int INITIAL_COMMENTS = 8; - - private InfoItemBuilder infoItemBuilder = null; - private int updateFlags = 0; private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1; private static final int RESOLUTIONS_MENU_UPDATE_FLAG = 0x2; @@ -133,8 +129,6 @@ public class VideoDetailFragment private boolean autoPlayEnabled; private boolean showRelatedStreams; private boolean showComments; - private boolean isCommentsSupported; - private boolean wasRelatedStreamsExpanded = false; @State protected int serviceId = Constants.NO_SERVICE_ID; @@ -144,7 +138,6 @@ public class VideoDetailFragment protected String url; private StreamInfo currentInfo; - private CommentsInfo commentsInfo; private Disposable currentWorker; @NonNull private CompositeDisposable disposables = new CompositeDisposable(); @@ -160,7 +153,6 @@ public class VideoDetailFragment private Spinner spinnerToolbar; - private ParallaxScrollView parallaxScrollRootView; private LinearLayout contentRootLayoutHiding; private View thumbnailBackgroundButton; @@ -193,21 +185,13 @@ public class VideoDetailFragment private ImageView thumbsDownImageView; private TextView thumbsDisabledTextView; - private TextView nextStreamTitle; - private LinearLayout relatedStreamRootLayout; - private LinearLayout relatedStreamsView; - private ImageButton relatedStreamExpandButton; - - private LinearLayout commentsRootLayout; - private View commentsEmptyStateView; - private LinearLayout commentsView; - private ImageButton commentsExpandButton; - private Disposable commentsDisposable; - - private TabHost tabHost; - private static final String COMMENTS_TAB_TAG = "CommentsTab"; - private static final String RELATED_TAB_TAG = "RelatedTab"; + private static final String COMMENTS_TAB_TAG = "COMMENTS"; + private static final String RELATED_TAB_TAG = "NEXT VIDEO"; + private AppBarLayout appBarLayout; + private ViewPager viewPager; + private TabAdaptor pageAdapter; + private TabLayout tabLayout; /*////////////////////////////////////////////////////////////////////////*/ @@ -247,7 +231,6 @@ public class VideoDetailFragment public void onPause() { super.onPause(); if (currentWorker != null) currentWorker.dispose(); - if (commentsDisposable != null) commentsDisposable.dispose(); } @Override @@ -256,10 +239,9 @@ public class VideoDetailFragment if (updateFlags != 0) { if (!isLoading.get() && currentInfo != null) { - if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) - initRelatedVideos(currentInfo); + if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) startLoading(false); if ((updateFlags & RESOLUTIONS_MENU_UPDATE_FLAG) != 0) setupActionBar(currentInfo); - if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) initComments(commentsInfo); + if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) startLoading(false); } if ((updateFlags & TOOLBAR_ITEMS_UPDATE_FLAG) != 0 @@ -273,8 +255,6 @@ public class VideoDetailFragment // Check if it was loading when the fragment was stopped/paused, if (wasLoading.getAndSet(false)) { selectAndLoadVideo(serviceId, url, name); - }else{ - loadComments(false); } } @@ -285,10 +265,8 @@ public class VideoDetailFragment .unregisterOnSharedPreferenceChangeListener(this); if (currentWorker != null) currentWorker.dispose(); - if (commentsDisposable != null) commentsDisposable.dispose(); if (disposables != null) disposables.clear(); currentWorker = null; - commentsDisposable = null; disposables = null; } @@ -339,7 +317,6 @@ public class VideoDetailFragment private static final String INFO_KEY = "info_key"; private static final String STACK_KEY = "stack_key"; - private static final String WAS_RELATED_EXPANDED_KEY = "was_related_expanded_key"; @Override public void onSaveInstanceState(Bundle outState) { @@ -348,10 +325,6 @@ public class VideoDetailFragment // Check if the next video label and video is visible, // if it is, include the two elements in the next check int nextCount = currentInfo != null && currentInfo.getNextVideo() != null ? 2 : 0; - if (relatedStreamsView != null - && relatedStreamsView.getChildCount() > INITIAL_RELATED_VIDEOS + nextCount) { - outState.putSerializable(WAS_RELATED_EXPANDED_KEY, true); - } if (!isLoading.get() && currentInfo != null && isVisible()) { outState.putSerializable(INFO_KEY, currentInfo); @@ -364,7 +337,6 @@ public class VideoDetailFragment protected void onRestoreInstanceState(@NonNull Bundle savedState) { super.onRestoreInstanceState(savedState); - wasRelatedStreamsExpanded = savedState.getBoolean(WAS_RELATED_EXPANDED_KEY, false); Serializable serializable = savedState.getSerializable(INFO_KEY); if (serializable instanceof StreamInfo) { //noinspection unchecked @@ -432,12 +404,6 @@ public class VideoDetailFragment case R.id.detail_title_root_layout: toggleTitleAndDescription(); break; - case R.id.detail_related_streams_expand: - toggleExpandRelatedVideos(currentInfo); - break; - case R.id.detail_comments_expand: - toggleExpandComments(commentsInfo); - break; } } @@ -472,41 +438,6 @@ public class VideoDetailFragment } } - private void toggleExpandRelatedVideos(StreamInfo info) { - if (DEBUG) Log.d(TAG, "toggleExpandRelatedVideos() called with: info = [" + info + "]"); - if (!showRelatedStreams) return; - - int nextCount = info.getNextVideo() != null ? 2 : 0; - int initialCount = INITIAL_RELATED_VIDEOS + nextCount; - - if (relatedStreamsView.getChildCount() > initialCount) { - relatedStreamsView.removeViews(initialCount, - relatedStreamsView.getChildCount() - (initialCount)); - relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable( - activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand))); - return; - } - - //Log.d(TAG, "toggleExpandRelatedVideos() called with: info = [" + info + "], from = [" + INITIAL_RELATED_VIDEOS + "]"); - for (int i = INITIAL_RELATED_VIDEOS; i < info.getRelatedStreams().size(); i++) { - InfoItem item = info.getRelatedStreams().get(i); - //Log.d(TAG, "i = " + i); - relatedStreamsView.addView(infoItemBuilder.buildView(relatedStreamsView, item)); - } - relatedStreamExpandButton.setImageDrawable( - ContextCompat.getDrawable(activity, - ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.collapse))); - } - - - private void toggleExpandComments(CommentsInfo info) { - if (DEBUG) Log.d(TAG, "toggleExpandComments() called with: info = [" + info + "]"); - if (!showComments || null == info) return; - - NavigationHelper.openCommentsFragment(getFragmentManager(), serviceId, url, name); - - } - /*////////////////////////////////////////////////////////////////////////// // Init //////////////////////////////////////////////////////////////////////////*/ @@ -516,8 +447,6 @@ public class VideoDetailFragment super.initViews(rootView, savedInstanceState); spinnerToolbar = activity.findViewById(R.id.toolbar).findViewById(R.id.toolbar_spinner); - parallaxScrollRootView = rootView.findViewById(R.id.detail_main_content); - thumbnailBackgroundButton = rootView.findViewById(R.id.detail_thumbnail_root_layout); thumbnailImageView = rootView.findViewById(R.id.detail_thumbnail_image_view); thumbnailPlayButton = rootView.findViewById(R.id.detail_thumbnail_play_button); @@ -553,67 +482,21 @@ public class VideoDetailFragment uploaderTextView = rootView.findViewById(R.id.detail_uploader_text_view); uploaderThumb = rootView.findViewById(R.id.detail_uploader_thumbnail_view); - StreamingService service = null; - try { - service = NewPipe.getService(serviceId); - } catch (ExtractionException e) { - onError(e); - } + appBarLayout = rootView.findViewById(R.id.appbarlayout); + viewPager = rootView.findViewById(R.id.viewpager); + pageAdapter = new TabAdaptor(getChildFragmentManager()); + viewPager.setAdapter(pageAdapter); + tabLayout = rootView.findViewById(R.id.tablayout); + tabLayout.setupWithViewPager(viewPager); - if (service.isCommentsSupported()) { - isCommentsSupported = true; - initTabs(rootView); - } - - relatedStreamRootLayout = rootView.findViewById(R.id.detail_related_streams_root_layout); - nextStreamTitle = rootView.findViewById(R.id.detail_next_stream_title); - relatedStreamsView = rootView.findViewById(R.id.detail_related_streams_view); - relatedStreamExpandButton = rootView.findViewById(R.id.detail_related_streams_expand); - - commentsRootLayout = rootView.findViewById(R.id.detail_comments_root_layout); - commentsEmptyStateView = rootView.findViewById(R.id.comments_empty_state_view); - commentsView = rootView.findViewById(R.id.detail_comments_view); - commentsExpandButton = rootView.findViewById(R.id.detail_comments_expand); - - infoItemBuilder = new InfoItemBuilder(activity); setHeightThumbnail(); } - private void initTabs(View rootView) { - tabHost = (TabHost) rootView.findViewById(R.id.tab_host); - tabHost.setup(); - - TabHost.TabSpec commentsTab = tabHost.newTabSpec(COMMENTS_TAB_TAG); - commentsTab.setContent(R.id.detail_comments_root_layout); - commentsTab.setIndicator(getString(R.string.comments)); - - TabHost.TabSpec relatedVideosTab = tabHost.newTabSpec(RELATED_TAB_TAG); - relatedVideosTab.setContent(R.id.detail_related_streams_root_layout); - relatedVideosTab.setIndicator(getString(R.string.next_video_title)); - - tabHost.addTab(commentsTab); - tabHost.addTab(relatedVideosTab); - - //show comments tab by default - tabHost.setCurrentTabByTag(COMMENTS_TAB_TAG); - } - @Override protected void initListeners() { super.initListeners(); - infoItemBuilder.setOnStreamSelectedListener(new OnClickGesture() { - @Override - public void selected(StreamInfoItem selectedItem) { - selectAndLoadVideo(selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName()); - } - - @Override - public void held(StreamInfoItem selectedItem) { - showStreamDialog(selectedItem); - } - }); videoTitleRoot.setOnClickListener(this); uploaderRootLayout.setOnClickListener(this); @@ -623,8 +506,6 @@ public class VideoDetailFragment detailControlsAddToPlaylist.setOnClickListener(this); detailControlsDownload.setOnClickListener(this); detailControlsDownload.setOnLongClickListener(this); - relatedStreamExpandButton.setOnClickListener(this); - commentsExpandButton.setOnClickListener(this); detailControlsBackground.setLongClickable(true); detailControlsPopup.setLongClickable(true); @@ -707,98 +588,6 @@ public class VideoDetailFragment } } - private void initRelatedVideos(StreamInfo info) { - if (relatedStreamsView.getChildCount() > 0) relatedStreamsView.removeAllViews(); - - if (info.getNextVideo() != null && showRelatedStreams) { - nextStreamTitle.setVisibility(View.VISIBLE); - relatedStreamsView.addView( - infoItemBuilder.buildView(relatedStreamsView, info.getNextVideo())); - relatedStreamsView.addView(getSeparatorView()); - showRelatedStreamsIfSelected(); - } else nextStreamTitle.setVisibility(View.GONE); - - if (info.getRelatedStreams() != null - && !info.getRelatedStreams().isEmpty() && showRelatedStreams) { - //long first = System.nanoTime(), each; - int to = info.getRelatedStreams().size() >= INITIAL_RELATED_VIDEOS - ? INITIAL_RELATED_VIDEOS - : info.getRelatedStreams().size(); - for (int i = 0; i < to; i++) { - InfoItem item = info.getRelatedStreams().get(i); - //each = System.nanoTime(); - relatedStreamsView.addView(infoItemBuilder.buildView(relatedStreamsView, item)); - //if (DEBUG) Log.d(TAG, "each took " + ((System.nanoTime() - each) / 1000000L) + "ms"); - } - //if (DEBUG) Log.d(TAG, "Total time " + ((System.nanoTime() - first) / 1000000L) + "ms"); - - showRelatedStreamsIfSelected(); - relatedStreamExpandButton.setVisibility(View.VISIBLE); - - relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable( - activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand))); - } else { - if (info.getNextVideo() == null) relatedStreamRootLayout.setVisibility(View.GONE); - relatedStreamExpandButton.setVisibility(View.GONE); - } - - } - - private void showRelatedStreamsIfSelected() { - if (null == tabHost || tabHost.getCurrentTabTag().contentEquals(RELATED_TAB_TAG)) { - relatedStreamRootLayout.setVisibility(View.VISIBLE); - } - } - - private void initComments(CommentsInfo info) { - clearComments(); - - if(null == info || null == info.getRelatedItems() || info.getRelatedItems().size() == 0){ - commentsEmptyStateView.setVisibility(View.VISIBLE); - return; - } - commentsEmptyStateView.setVisibility(View.GONE); - - List initialComments = info.getRelatedItems(); - if (null != info && initialComments != null - && !initialComments.isEmpty() && showComments) { - //long first = System.nanoTime(), each; - int to = initialComments.size() >= INITIAL_COMMENTS - ? INITIAL_COMMENTS - : initialComments.size(); - for (int i = 0; i < to; i++) { - InfoItem item = initialComments.get(i); - //each = System.nanoTime(); - commentsView.addView(infoItemBuilder.buildView(commentsView, item)); - //if (DEBUG) Log.d(TAG, "each took " + ((System.nanoTime() - each) / 1000000L) + "ms"); - } - //if (DEBUG) Log.d(TAG, "Total time " + ((System.nanoTime() - first) / 1000000L) + "ms"); - - showCommentsIfSelected(); - if(initialComments.size() > INITIAL_COMMENTS){ - commentsExpandButton.setVisibility(View.VISIBLE); - commentsExpandButton.setImageDrawable(ContextCompat.getDrawable( - activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand))); - }else{ - commentsExpandButton.setVisibility(View.GONE); - } - } else { - commentsRootLayout.setVisibility(View.GONE); - } - - } - - private void showCommentsIfSelected() { - if (null == tabHost || tabHost.getCurrentTabTag().contentEquals(COMMENTS_TAB_TAG)) { - commentsRootLayout.setVisibility(View.VISIBLE); - } - } - - private void clearComments(){ - if (commentsView.getChildCount() > 0) commentsView.removeAllViews(); - commentsExpandButton.setVisibility(View.GONE); - } - /*////////////////////////////////////////////////////////////////////////// // Menu //////////////////////////////////////////////////////////////////////////*/ @@ -979,23 +768,18 @@ public class VideoDetailFragment setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName()); pushToStack(serviceId, url, name); showLoading(); + initTabs(); - Log.d(TAG, "prepareAndHandleInfo() called parallaxScrollRootView.getScrollY(): " - + parallaxScrollRootView.getScrollY()); - final boolean greaterThanThreshold = parallaxScrollRootView.getScrollY() > (int) - (getResources().getDisplayMetrics().heightPixels * .1f); - - if (scrollToTop) parallaxScrollRootView.smoothScrollTo(0, 0); + if (scrollToTop) appBarLayout.setExpanded(true, true); animateView(contentRootLayoutHiding, - false, - greaterThanThreshold ? 250 : 0, 0, () -> { + false, 0, 0, () -> { handleResult(info); showContentWithAnimation(120, 0, .01f); }); } protected void prepareAndLoadInfo() { - parallaxScrollRootView.smoothScrollTo(0, 0); + appBarLayout.setExpanded(true, true); pushToStack(serviceId, url, name); startLoading(false); } @@ -1004,6 +788,7 @@ public class VideoDetailFragment public void startLoading(boolean forceLoad) { super.startLoading(forceLoad); + initTabs(); currentInfo = null; if (currentWorker != null) currentWorker.dispose(); @@ -1020,26 +805,29 @@ public class VideoDetailFragment onError(throwable); }); - loadComments(forceLoad); - } - private void loadComments(boolean forceLoad) { - if(isCommentsSupported && showComments){ - clearComments(); - commentsInfo = null; - if (commentsDisposable != null) commentsDisposable.dispose(); + private void initTabs() { + pageAdapter.clearAllItems(); - commentsDisposable = ExtractorHelper.getCommentsInfo(serviceId, url, forceLoad) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe((@NonNull CommentsInfo result) -> { - commentsInfo = result; - showCommentsWithAnimation(120, 0,0); - initComments(commentsInfo); - }, (@NonNull Throwable throwable) -> { - onCommentsError(throwable); - }); + if(shouldShowComments()){ + pageAdapter.addFragment(CommentsFragment.getInstance(serviceId, url, name), COMMENTS_TAB_TAG); + } + + if(showRelatedStreams){ + pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG); + } + + if(pageAdapter.getCount() < 2){ + tabLayout.setVisibility(View.GONE); + } + } + + private boolean shouldShowComments() { + try { + return showComments && NewPipe.getService(serviceId).isCommentsSupported(); + } catch (ExtractionException e) { + return false; } } @@ -1230,41 +1018,6 @@ public class VideoDetailFragment .setInterpolator(new FastOutSlowInInterpolator()) .start(); - if (showRelatedStreams && (null == tabHost || tabHost.getCurrentTabTag().contentEquals(RELATED_TAB_TAG))) { - relatedStreamRootLayout.animate().setListener(null).cancel(); - relatedStreamRootLayout.setAlpha(0f); - relatedStreamRootLayout.setTranslationY(translationY); - relatedStreamRootLayout.setVisibility(View.VISIBLE); - relatedStreamRootLayout.animate() - .alpha(1f) - .translationY(0) - .setStartDelay((long) (duration * .8f) + delay) - .setDuration(duration) - .setInterpolator(new FastOutSlowInInterpolator()) - .start(); - } - - } - - private void showCommentsWithAnimation(long duration, - long delay, - @FloatRange(from = 0.0f, to = 1.0f) float translationPercent) { - int translationY = (int) (getResources().getDisplayMetrics().heightPixels * - (translationPercent > 0.0f ? translationPercent : .06f)); - - if (showComments && (null == tabHost || tabHost.getCurrentTabTag().contentEquals(COMMENTS_TAB_TAG))) { - commentsRootLayout.animate().setListener(null).cancel(); - commentsRootLayout.setAlpha(0f); - commentsRootLayout.setTranslationY(translationY); - commentsRootLayout.setVisibility(View.VISIBLE); - commentsRootLayout.animate() - .alpha(1f) - .translationY(0) - .setStartDelay((long) (duration * .8f) + delay) - .setDuration(duration) - .setInterpolator(new FastOutSlowInInterpolator()) - .start(); - } } protected void setInitialData(int serviceId, String url, String name) { @@ -1324,6 +1077,11 @@ public class VideoDetailFragment super.handleResult(info); setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName()); + + if(showRelatedStreams){ + pageAdapter.updateItem(RELATED_TAB_TAG, RelatedVideosFragment.getInstance(currentInfo)); + } + pushToStack(serviceId, url, name); animateView(thumbnailPlayButton, true, 200); @@ -1398,12 +1156,6 @@ public class VideoDetailFragment animateView(spinnerToolbar, true, 500); setupActionBar(info); initThumbnailViews(info); - initRelatedVideos(info); - - if (wasRelatedStreamsExpanded) { - toggleExpandRelatedVideos(currentInfo); - wasRelatedStreamsExpanded = false; - } setTitleToUrl(info.getServiceId(), info.getUrl(), info.getName()); setTitleToUrl(info.getServiceId(), info.getOriginalUrl(), info.getName()); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java index 02815407a..e7778c905 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java @@ -71,7 +71,6 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView; public class CommentsFragment extends BaseListInfoFragment { private CompositeDisposable disposables = new CompositeDisposable(); - private boolean initialLoad = true; /*////////////////////////////////////////////////////////////////////////// // Views //////////////////////////////////////////////////////////////////////////*/ @@ -94,11 +93,6 @@ public class CommentsFragment extends BaseListInfoFragment { public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); mIsVisibleToUser = isVisibleToUser; - if(activity != null - && useAsFrontPage - && isVisibleToUser) { - setTitle(currentInfo != null ? currentInfo.getName() : name); - } } @Override @@ -117,15 +111,6 @@ public class CommentsFragment extends BaseListInfoFragment { if (disposables != null) disposables.clear(); } - /*////////////////////////////////////////////////////////////////////////// - // Init - //////////////////////////////////////////////////////////////////////////*/ - - - /*////////////////////////////////////////////////////////////////////////// - // Menu - //////////////////////////////////////////////////////////////////////////*/ - /*////////////////////////////////////////////////////////////////////////// // Load and handle @@ -153,10 +138,6 @@ public class CommentsFragment extends BaseListInfoFragment { @Override public void handleResult(@NonNull CommentsInfo result) { super.handleResult(result); - if(initialLoad){ - itemsList.smoothScrollToPosition(VideoDetailFragment.INITIAL_COMMENTS); - initialLoad = false; - } if (!result.getErrors().isEmpty()) { showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); @@ -186,12 +167,7 @@ public class CommentsFragment extends BaseListInfoFragment { protected boolean onError(Throwable exception) { if (super.onError(exception)) return true; - int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error; - onUnrecoverableError(exception, - UserAction.REQUESTED_COMMENTS, - NewPipe.getNameOfService(serviceId), - url, - errorId); + showSnackBarError(exception, UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(serviceId), url, R.string.error_unable_to_load_comments); return true; } @@ -201,6 +177,11 @@ public class CommentsFragment extends BaseListInfoFragment { @Override public void setTitle(String title) { - super.setTitle(title); + return; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + return; } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java new file mode 100644 index 000000000..08a6a3bc3 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java @@ -0,0 +1,150 @@ +package org.schabi.newpipe.fragments.list.videos; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.schabi.newpipe.R; +import org.schabi.newpipe.extractor.InfoItem; +import org.schabi.newpipe.extractor.ListExtractor; +import org.schabi.newpipe.extractor.ListInfo; +import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.comments.CommentsInfo; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.kiosk.KioskInfo; +import org.schabi.newpipe.extractor.stream.StreamInfo; +import org.schabi.newpipe.extractor.stream.StreamInfoItem; +import org.schabi.newpipe.fragments.list.BaseListInfoFragment; +import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.util.ExtractorHelper; +import org.schabi.newpipe.util.RelatedStreamInfo; + +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.disposables.CompositeDisposable; + +public class RelatedVideosFragment extends BaseListInfoFragment { + + private CompositeDisposable disposables = new CompositeDisposable(); + private RelatedStreamInfo relatedStreamInfo; + /*////////////////////////////////////////////////////////////////////////// + // Views + //////////////////////////////////////////////////////////////////////////*/ + + + + private boolean mIsVisibleToUser = false; + + public static RelatedVideosFragment getInstance(StreamInfo info) { + RelatedVideosFragment instance = new RelatedVideosFragment(); + instance.setInitialData(info); + return instance; + } + + /*////////////////////////////////////////////////////////////////////////// + // LifeCycle + //////////////////////////////////////////////////////////////////////////*/ + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + mIsVisibleToUser = isVisibleToUser; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_related_streams, container, false); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (disposables != null) disposables.clear(); + } + + @Override + protected Single loadMoreItemsLogic() { + return Single.fromCallable(() -> ListExtractor.InfoItemsPage.emptyPage()); + } + + @Override + protected Single loadResult(boolean forceLoad) { + return Single.fromCallable(() -> relatedStreamInfo); + } + + /*////////////////////////////////////////////////////////////////////////// + // Contract + //////////////////////////////////////////////////////////////////////////*/ + + @Override + public void showLoading() { + super.showLoading(); + } + + @Override + public void handleResult(@NonNull RelatedStreamInfo result) { + super.handleResult(result); + + if (!result.getErrors().isEmpty()) { + showSnackBarError(result.getErrors(), UserAction.REQUESTED_STREAM, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); + } + + if (disposables != null) disposables.clear(); + } + + @Override + public void handleNextItems(ListExtractor.InfoItemsPage result) { + super.handleNextItems(result); + + if (!result.getErrors().isEmpty()) { + showSnackBarError(result.getErrors(), + UserAction.REQUESTED_STREAM, + NewPipe.getNameOfService(serviceId), + "Get next page of: " + url, + R.string.general_error); + } + } + + /*////////////////////////////////////////////////////////////////////////// + // OnError + //////////////////////////////////////////////////////////////////////////*/ + + @Override + protected boolean onError(Throwable exception) { + if (super.onError(exception)) return true; + + showSnackBarError(exception, UserAction.REQUESTED_STREAM, NewPipe.getNameOfService(serviceId), url, R.string.general_error); + return true; + } + + /*////////////////////////////////////////////////////////////////////////// + // Utils + //////////////////////////////////////////////////////////////////////////*/ + + @Override + public void setTitle(String title) { + return; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + return; + } + + private void setInitialData(StreamInfo info) { + super.setInitialData(info.getServiceId(), info.getUrl(), info.getName()); + this.relatedStreamInfo = RelatedStreamInfo.getInfo(info); + } +} diff --git a/app/src/main/java/org/schabi/newpipe/util/RelatedStreamInfo.java b/app/src/main/java/org/schabi/newpipe/util/RelatedStreamInfo.java new file mode 100644 index 000000000..c81100703 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/util/RelatedStreamInfo.java @@ -0,0 +1,23 @@ +package org.schabi.newpipe.util; + +import org.schabi.newpipe.extractor.InfoItem; +import org.schabi.newpipe.extractor.ListInfo; +import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; +import org.schabi.newpipe.extractor.stream.StreamInfo; + +import java.util.Collections; + +public class RelatedStreamInfo extends ListInfo { + + + public RelatedStreamInfo(int serviceId, ListLinkHandler listUrlIdHandler, String name) { + super(serviceId, listUrlIdHandler, name); + } + + public static RelatedStreamInfo getInfo(StreamInfo info) { + ListLinkHandler handler = new ListLinkHandler(info.getOriginalUrl(), info.getUrl(), info.getId(), Collections.emptyList(), null); + RelatedStreamInfo relatedStreamInfo = new RelatedStreamInfo(info.getServiceId(), handler, info.getName()); + relatedStreamInfo.setRelatedItems(info.getRelatedStreams()); + return relatedStreamInfo; + } +} diff --git a/app/src/main/res/layout/fragment_comments.xml b/app/src/main/res/layout/fragment_comments.xml index 83e788070..57ca28688 100644 --- a/app/src/main/res/layout/fragment_comments.xml +++ b/app/src/main/res/layout/fragment_comments.xml @@ -25,7 +25,7 @@ android:id="@+id/empty_state_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_centerInParent="true" + android:layout_centerHorizontal="true" android:orientation="vertical" android:paddingTop="90dp" android:visibility="gone" diff --git a/app/src/main/res/layout/fragment_related_streams.xml b/app/src/main/res/layout/fragment_related_streams.xml new file mode 100644 index 000000000..36c9c1d31 --- /dev/null +++ b/app/src/main/res/layout/fragment_related_streams.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml index 870043eb1..25eac35cf 100644 --- a/app/src/main/res/layout/fragment_video_detail.xml +++ b/app/src/main/res/layout/fragment_video_detail.xml @@ -7,101 +7,107 @@ android:layout_height="match_parent" android:focusableInTouchMode="true"> - + android:layout_height="match_parent"> - - + android:layout_height="wrap_content"> - - + app:layout_scrollFlags="scroll"> - + + android:background="@android:color/black" + android:clickable="true" + android:focusable="true" + android:foreground="?attr/selectableItemBackground" + app:layout_collapseMode="parallax"> - + - + - - + + + + + + + android:layout_height="wrap_content" + android:background="?android:windowBackground" + app:layout_scrollFlags="scroll"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + From b8865e925d498cb9c728c083e8719732c54afc6b Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Tue, 2 Oct 2018 20:56:14 +0530 Subject: [PATCH 13/37] added content setting to disable comments --- .../newpipe/fragments/detail/VideoDetailFragment.java | 11 +++++------ app/src/main/res/values/settings_keys.xml | 2 +- app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/content_settings.xml | 6 ++++++ 4 files changed, 14 insertions(+), 7 deletions(-) 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 ded6be349..67f86a905 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 @@ -216,7 +216,7 @@ public class VideoDetailFragment .getBoolean(getString(R.string.show_next_video_key), true); showComments = PreferenceManager.getDefaultSharedPreferences(activity) - .getBoolean(getString(R.string.show_comments), true); + .getBoolean(getString(R.string.show_comments_key), true); PreferenceManager.getDefaultSharedPreferences(activity) .registerOnSharedPreferenceChangeListener(this); @@ -305,7 +305,7 @@ public class VideoDetailFragment updateFlags |= RESOLUTIONS_MENU_UPDATE_FLAG; } else if (key.equals(getString(R.string.show_play_with_kodi_key))) { updateFlags |= TOOLBAR_ITEMS_UPDATE_FLAG; - } else if (key.equals(R.string.show_comments)) { + } else if (key.equals(getString(R.string.show_comments_key))) { showComments = sharedPreferences.getBoolean(key, true); updateFlags |= COMMENTS_UPDATE_FLAG; } @@ -815,11 +815,14 @@ public class VideoDetailFragment } if(showRelatedStreams){ + //temp empty fragment. will be updated in handleResult pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG); } if(pageAdapter.getCount() < 2){ tabLayout.setVisibility(View.GONE); + }else{ + tabLayout.setVisibility(View.VISIBLE); } } @@ -1247,8 +1250,4 @@ public class VideoDetailFragment showError(getString(R.string.blocked_by_gema), false, R.drawable.gruese_die_gema); } - - public void onCommentsError(Throwable exception) { - showSnackBarError(exception, UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(serviceId), url, R.string.error_unable_to_load_comments); - } } \ No newline at end of file diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index b110a6aa3..1a56e2d40 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -135,7 +135,7 @@ show_search_suggestions show_play_with_kodi show_next_video - show_comments + show_comments show_hold_to_append en GB diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3dbbc29cf..bd00ddce1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -76,6 +76,8 @@ Inexact seek allows the player to seek to positions faster with reduced precision Load thumbnails Disable to stop all thumbnails from loading and save on data and memory usage. Changing this will clear both in-memory and on-disk image cache. + Show comments + Disable to stop showing comments Image cache wiped Wipe cached metadata Remove all cached webpage data diff --git a/app/src/main/res/xml/content_settings.xml b/app/src/main/res/xml/content_settings.xml index fcf42b130..d641a1574 100644 --- a/app/src/main/res/xml/content_settings.xml +++ b/app/src/main/res/xml/content_settings.xml @@ -43,6 +43,12 @@ android:title="@string/download_thumbnail_title" android:summary="@string/download_thumbnail_summary"/> + + Date: Tue, 2 Oct 2018 21:30:11 +0530 Subject: [PATCH 14/37] update notify on dataset change --- .../newpipe/fragments/detail/TabAdaptor.java | 23 +++++++++++++------ .../fragments/detail/VideoDetailFragment.java | 3 +++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java index c091f45b2..2dd7071be 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java @@ -44,27 +44,20 @@ public class TabAdaptor extends FragmentPagerAdapter { public void addFragment(Fragment fragment, String title) { mFragmentList.add(fragment); mFragmentTitleList.add(title); - notifyDataSetChanged(); } public void clearAllItems() { mFragmentList.clear(); mFragmentTitleList.clear(); - notifyDataSetChanged(); } public void removeItem(int position){ mFragmentList.remove(position == 0 ? 0 : position - 1); mFragmentTitleList.remove(position == 0 ? 0 : position - 1); - notifyDataSetChanged(); } public void updateItem(int position, Fragment fragment){ mFragmentList.set(position, fragment); - // shift the ID returned by getItemId outside the range of all previous fragments - // https://stackoverflow.com/questions/10396321/remove-fragment-page-from-viewpager-in-android - baseId += getCount() + 1; - notifyDataSetChanged(); } public void updateItem(String title, Fragment fragment){ @@ -79,4 +72,20 @@ public class TabAdaptor extends FragmentPagerAdapter { if (mFragmentList.contains(object)) return mFragmentList.indexOf(object); else return POSITION_NONE; } + + /** + * Notify that the position of a fragment has been changed. + * Create a new ID for each position to force recreation of the fragment + * @param n number of items which have been changed + */ + public void notifyChangeInPosition(int n) { + // shift the ID returned by getItemId outside the range of all previous fragments + // https://stackoverflow.com/questions/10396321/remove-fragment-page-from-viewpager-in-android + baseId += getCount() + n; + } + + public void notifyDataSetUpdate(){ + notifyChangeInPosition(1); + notifyDataSetChanged(); + } } 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 67f86a905..76047b725 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 @@ -819,6 +819,8 @@ public class VideoDetailFragment pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG); } + pageAdapter.notifyDataSetUpdate(); + if(pageAdapter.getCount() < 2){ tabLayout.setVisibility(View.GONE); }else{ @@ -1083,6 +1085,7 @@ public class VideoDetailFragment if(showRelatedStreams){ pageAdapter.updateItem(RELATED_TAB_TAG, RelatedVideosFragment.getInstance(currentInfo)); + pageAdapter.notifyDataSetUpdate(); } pushToStack(serviceId, url, name); From 9fc38b5bb8a8fddb085a97220f7332c9df15ee21 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Wed, 17 Oct 2018 00:23:02 +0530 Subject: [PATCH 15/37] improved fling behavior, added tab indicator dots, added next video in related videos --- .../support/design/widget/FlingBehavior.java | 143 ++++++++++++++++++ .../newpipe/fragments/detail/TabAdaptor.java | 8 - .../fragments/detail/VideoDetailFragment.java | 25 --- .../fragments/list/BaseListFragment.java | 2 +- .../list/videos/RelatedVideosFragment.java | 68 +++++++-- .../newpipe/util/RelatedStreamInfo.java | 22 ++- app/src/main/res/drawable/default_dot.xml | 12 ++ app/src/main/res/drawable/selected_dot.xml | 12 ++ app/src/main/res/drawable/tab_selector.xml | 8 + app/src/main/res/layout/fragment_comments.xml | 3 +- .../res/layout/fragment_related_streams.xml | 3 +- .../main/res/layout/fragment_video_detail.xml | 30 ++-- .../res/layout/related_streams_header.xml | 33 ++++ app/src/main/res/values/strings.xml | 3 +- 14 files changed, 313 insertions(+), 59 deletions(-) create mode 100644 app/src/main/java/android/support/design/widget/FlingBehavior.java create mode 100644 app/src/main/res/drawable/default_dot.xml create mode 100644 app/src/main/res/drawable/selected_dot.xml create mode 100644 app/src/main/res/drawable/tab_selector.xml create mode 100644 app/src/main/res/layout/related_streams_header.xml diff --git a/app/src/main/java/android/support/design/widget/FlingBehavior.java b/app/src/main/java/android/support/design/widget/FlingBehavior.java new file mode 100644 index 000000000..217e3ae3a --- /dev/null +++ b/app/src/main/java/android/support/design/widget/FlingBehavior.java @@ -0,0 +1,143 @@ +package android.support.design.widget; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.util.AttributeSet; +import android.view.View; + +// check this https://github.com/ToDou/appbarlayout-spring-behavior/blob/master/appbarspring/src/main/java/android/support/design/widget/AppBarFlingFixBehavior.java +public final class FlingBehavior extends AppBarLayout.Behavior { + + private ValueAnimator mOffsetAnimator; + private static final int MAX_OFFSET_ANIMATION_DURATION = 600; // ms + + public FlingBehavior() { + } + + public FlingBehavior(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int type) { + return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes, type); + } + + @Override + public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed, int type) { + if (dy != 0) { + int val = child.getBottom(); + if (val != 0) { + int min, max; + if (dy < 0) { + // We're scrolling down + } else { + // We're scrolling up + min = -child.getUpNestedPreScrollRange(); + max = 0; + consumed[1] = scroll(coordinatorLayout, child, dy, min, max); + } + } + } + } + + @Override + public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) { + super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type); + } + + @Override + public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl, View target, int type) { + super.onStopNestedScroll(coordinatorLayout, abl, target, type); + } + + @Override + public boolean onMeasureChild(CoordinatorLayout parent, AppBarLayout child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { + return super.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed); + } + + @Override + public Parcelable onSaveInstanceState(CoordinatorLayout parent, AppBarLayout abl) { + return super.onSaveInstanceState(parent, abl); + } + + @Override + public void onRestoreInstanceState(CoordinatorLayout parent, AppBarLayout appBarLayout, Parcelable state) { + super.onRestoreInstanceState(parent, appBarLayout, state); + } + + @Override + public boolean onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull AppBarLayout child, @NonNull View target, float velocityX, float velocityY) { + + if (velocityY != 0) { + if (velocityY < 0) { + // We're flinging down + int val = child.getBottom(); + if (val != 0) { + final int targetScroll = + +child.getDownNestedPreScrollRange(); + animateOffsetTo(coordinatorLayout, child, targetScroll, velocityY); + } + + } else { + // We're flinging up + int val = child.getBottom(); + if (val != 0) { + final int targetScroll = -child.getUpNestedPreScrollRange(); + if (getTopBottomOffsetForScrollingSibling() > targetScroll) { + animateOffsetTo(coordinatorLayout, child, targetScroll, velocityY); + } + } + } + } + + return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY); + } + + private void animateOffsetTo(final CoordinatorLayout coordinatorLayout, + final AppBarLayout child, final int offset, float velocity) { + final int distance = Math.abs(getTopBottomOffsetForScrollingSibling() - offset); + + final int duration; + velocity = Math.abs(velocity); + if (velocity > 0) { + duration = 3 * Math.round(1000 * (distance / velocity)); + } else { + final float distanceRatio = (float) distance / child.getHeight(); + duration = (int) ((distanceRatio + 1) * 150); + } + + animateOffsetWithDuration(coordinatorLayout, child, offset, duration); + } + + private void animateOffsetWithDuration(final CoordinatorLayout coordinatorLayout, + final AppBarLayout child, final int offset, final int duration) { + final int currentOffset = getTopBottomOffsetForScrollingSibling(); + if (currentOffset == offset) { + if (mOffsetAnimator != null && mOffsetAnimator.isRunning()) { + mOffsetAnimator.cancel(); + } + return; + } + + if (mOffsetAnimator == null) { + mOffsetAnimator = new ValueAnimator(); + mOffsetAnimator.setInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR); + mOffsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animator) { + setHeaderTopBottomOffset(coordinatorLayout, child, + (Integer) animator.getAnimatedValue()); + } + }); + } else { + mOffsetAnimator.cancel(); + } + + mOffsetAnimator.setDuration(Math.min(duration, MAX_OFFSET_ANIMATION_DURATION)); + mOffsetAnimator.setIntValues(currentOffset, offset); + mOffsetAnimator.start(); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java index 2dd7071be..3ed247e50 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java @@ -1,10 +1,8 @@ package org.schabi.newpipe.fragments.detail; -import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; -import android.support.v4.view.PagerAdapter; import java.util.ArrayList; import java.util.List; @@ -29,12 +27,6 @@ public class TabAdaptor extends FragmentPagerAdapter { return mFragmentList.size(); } - @Nullable - @Override - public CharSequence getPageTitle(int position) { - return mFragmentTitleList.get(position); - } - @Override public long getItemId(int position) { // give an ID different from position when position has been changed 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 76047b725..d3f602ebd 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 @@ -29,7 +29,6 @@ import android.text.method.LinkMovementMethod; import android.text.util.Linkify; import android.util.DisplayMetrics; import android.util.Log; -import android.util.TypedValue; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -39,7 +38,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.FrameLayout; -import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; @@ -56,8 +54,6 @@ import org.schabi.newpipe.ReCaptchaActivity; import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.StreamingService; -import org.schabi.newpipe.extractor.comments.CommentsInfo; import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ParsingException; @@ -72,7 +68,6 @@ import org.schabi.newpipe.fragments.BackPressable; import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.list.comments.CommentsFragment; import org.schabi.newpipe.fragments.list.videos.RelatedVideosFragment; -import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemDialog; import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; import org.schabi.newpipe.local.history.HistoryRecordManager; @@ -91,11 +86,9 @@ import org.schabi.newpipe.util.InfoCache; import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; -import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.PermissionHelper; import org.schabi.newpipe.util.StreamItemAdapter; import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper; -import org.schabi.newpipe.util.ThemeHelper; import java.io.Serializable; import java.util.Collection; @@ -964,24 +957,6 @@ public class VideoDetailFragment })); } - private View getSeparatorView() { - View separator = new View(activity); - LinearLayout.LayoutParams params = - new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1); - int m8 = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, 8, getResources().getDisplayMetrics()); - int m5 = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics()); - params.setMargins(m8, m5, m8, m5); - separator.setLayoutParams(params); - - TypedValue typedValue = new TypedValue(); - activity.getTheme().resolveAttribute(R.attr.separator_color, typedValue, true); - separator.setBackgroundColor(typedValue.data); - - return separator; - } - private void setHeightThumbnail() { final DisplayMetrics metrics = getResources().getDisplayMetrics(); boolean isPortrait = metrics.heightPixels > metrics.widthPixels; 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 cd557c931..672d8c2be 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 @@ -22,9 +22,9 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.OnScrollBelowItemsListener; -import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; import org.schabi.newpipe.info_list.InfoItemDialog; import org.schabi.newpipe.info_list.InfoListAdapter; +import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; import org.schabi.newpipe.player.playqueue.SinglePlayQueue; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.util.NavigationHelper; diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java index 08a6a3bc3..44c7c6787 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java @@ -1,7 +1,9 @@ package org.schabi.newpipe.fragments.list.videos; import android.content.Context; +import android.content.SharedPreferences; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.LayoutInflater; @@ -9,34 +11,31 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.CompoundButton; +import android.widget.Switch; import org.schabi.newpipe.R; -import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor; -import org.schabi.newpipe.extractor.ListInfo; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.comments.CommentsInfo; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.extractor.kiosk.KioskInfo; import org.schabi.newpipe.extractor.stream.StreamInfo; -import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.report.UserAction; -import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.RelatedStreamInfo; -import java.util.List; +import java.io.Serializable; import io.reactivex.Single; import io.reactivex.disposables.CompositeDisposable; -public class RelatedVideosFragment extends BaseListInfoFragment { +public class RelatedVideosFragment extends BaseListInfoFragment implements SharedPreferences.OnSharedPreferenceChangeListener{ private CompositeDisposable disposables = new CompositeDisposable(); private RelatedStreamInfo relatedStreamInfo; /*////////////////////////////////////////////////////////////////////////// // Views //////////////////////////////////////////////////////////////////////////*/ + private View headerRootLayout; + private Switch aSwitch; @@ -74,6 +73,28 @@ public class RelatedVideosFragment extends BaseListInfoFragment loadMoreItemsLogic() { return Single.fromCallable(() -> ListExtractor.InfoItemsPage.emptyPage()); @@ -145,6 +166,33 @@ public class RelatedVideosFragment extends BaseListInfoFragment { + private StreamInfoItem nextStream; public RelatedStreamInfo(int serviceId, ListLinkHandler listUrlIdHandler, String name) { super(serviceId, listUrlIdHandler, name); @@ -17,7 +21,21 @@ public class RelatedStreamInfo extends ListInfo { public static RelatedStreamInfo getInfo(StreamInfo info) { ListLinkHandler handler = new ListLinkHandler(info.getOriginalUrl(), info.getUrl(), info.getId(), Collections.emptyList(), null); RelatedStreamInfo relatedStreamInfo = new RelatedStreamInfo(info.getServiceId(), handler, info.getName()); - relatedStreamInfo.setRelatedItems(info.getRelatedStreams()); - return relatedStreamInfo; + List streams = new ArrayList<>(); + if(info.getNextVideo() != null){ + streams.add(info.getNextVideo()); + } + streams.addAll(info.getRelatedStreams()); + relatedStreamInfo.setRelatedItems(streams); + relatedStreamInfo.setNextStream(info.getNextVideo()); + return relatedStreamInfo; + } + + public StreamInfoItem getNextStream() { + return nextStream; + } + + public void setNextStream(StreamInfoItem nextStream) { + this.nextStream = nextStream; } } diff --git a/app/src/main/res/drawable/default_dot.xml b/app/src/main/res/drawable/default_dot.xml new file mode 100644 index 000000000..3380dca3b --- /dev/null +++ b/app/src/main/res/drawable/default_dot.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selected_dot.xml b/app/src/main/res/drawable/selected_dot.xml new file mode 100644 index 000000000..017e99d43 --- /dev/null +++ b/app/src/main/res/drawable/selected_dot.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tab_selector.xml b/app/src/main/res/drawable/tab_selector.xml new file mode 100644 index 000000000..b7307674b --- /dev/null +++ b/app/src/main/res/drawable/tab_selector.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_comments.xml b/app/src/main/res/layout/fragment_comments.xml index 57ca28688..9ace63d4d 100644 --- a/app/src/main/res/layout/fragment_comments.xml +++ b/app/src/main/res/layout/fragment_comments.xml @@ -65,6 +65,7 @@ android:layout_width="match_parent" android:layout_height="4dp" android:background="?attr/toolbar_shadow_drawable" - android:layout_alignParentTop="true"/> + android:layout_alignParentTop="true" + android:visibility="gone"/> diff --git a/app/src/main/res/layout/fragment_related_streams.xml b/app/src/main/res/layout/fragment_related_streams.xml index 36c9c1d31..c12630392 100644 --- a/app/src/main/res/layout/fragment_related_streams.xml +++ b/app/src/main/res/layout/fragment_related_streams.xml @@ -65,6 +65,7 @@ android:layout_width="match_parent" android:layout_height="4dp" android:background="?attr/toolbar_shadow_drawable" - android:layout_alignParentTop="true"/> + android:layout_alignParentTop="true" + android:visibility="gone"/> diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml index 25eac35cf..906246bd0 100644 --- a/app/src/main/res/layout/fragment_video_detail.xml +++ b/app/src/main/res/layout/fragment_video_detail.xml @@ -10,12 +10,16 @@ + android:layout_height="match_parent" + android:fitsSystemWindows="true"> + android:layout_height="wrap_content" + android:fitsSystemWindows="true" + app:elevation="0dp" + app:layout_behavior="android.support.design.widget.FlingBehavior"> - - - - + + + + + + diff --git a/app/src/main/res/layout/related_streams_header.xml b/app/src/main/res/layout/related_streams_header.xml new file mode 100644 index 000000000..5be7c928d --- /dev/null +++ b/app/src/main/res/layout/related_streams_header.xml @@ -0,0 +1,33 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bd00ddce1..354778e6d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -95,7 +95,8 @@ Resume on focus gain Continue playing after interruptions (e.g. phone calls) Download - Next video + Up next + Autoplay Show \'next\' and \'similar\' videos Show \"hold to append\" tip Show tip when background or popup button is pressed on video details page From fa5896ee5bfda7a47d04c856767f14e02a0677ba Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Fri, 19 Oct 2018 18:44:03 +0530 Subject: [PATCH 16/37] fixed screen rotation for viewpager --- .../newpipe/fragments/detail/TabAdaptor.java | 28 ++++++------------- .../list/videos/RelatedVideosFragment.java | 2 -- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java index 3ed247e50..27cc3ec8a 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/TabAdaptor.java @@ -3,6 +3,7 @@ package org.schabi.newpipe.fragments.detail; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; +import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; @@ -11,10 +12,11 @@ public class TabAdaptor extends FragmentPagerAdapter { private final List mFragmentList = new ArrayList<>(); private final List mFragmentTitleList = new ArrayList<>(); - int baseId = 0; + private final FragmentManager fragmentManager; public TabAdaptor(FragmentManager fm) { super(fm); + this.fragmentManager = fm; } @Override @@ -27,12 +29,6 @@ public class TabAdaptor extends FragmentPagerAdapter { return mFragmentList.size(); } - @Override - public long getItemId(int position) { - // give an ID different from position when position has been changed - return baseId + position; - } - public void addFragment(Fragment fragment, String title) { mFragmentList.add(fragment); mFragmentTitleList.add(title); @@ -65,19 +61,13 @@ public class TabAdaptor extends FragmentPagerAdapter { else return POSITION_NONE; } - /** - * Notify that the position of a fragment has been changed. - * Create a new ID for each position to force recreation of the fragment - * @param n number of items which have been changed - */ - public void notifyChangeInPosition(int n) { - // shift the ID returned by getItemId outside the range of all previous fragments - // https://stackoverflow.com/questions/10396321/remove-fragment-page-from-viewpager-in-android - baseId += getCount() + n; - } - public void notifyDataSetUpdate(){ - notifyChangeInPosition(1); notifyDataSetChanged(); } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + fragmentManager.beginTransaction().remove((Fragment) object).commitNowAllowingStateLoss(); + } + } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java index 44c7c6787..694731c69 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java @@ -37,8 +37,6 @@ public class RelatedVideosFragment extends BaseListInfoFragment Date: Tue, 4 Dec 2018 23:37:02 +0530 Subject: [PATCH 17/37] removed useless log statement --- .../org/schabi/newpipe/fragments/list/BaseListFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e46606871..b61fe0d02 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 @@ -224,7 +224,7 @@ public abstract class BaseListFragment extends BaseStateFragment implem infoListAdapter.setOnCommentsSelectedListener(new OnClickGesture() { @Override public void selected(CommentsInfoItem selectedItem) { - //Log.d("comments" , "this comment was clicked" + selectedItem.getCommentText()); + onItemSelected(selectedItem); } }); From c1a67ff1f8b07d6427201395753c1edb8eb4e308 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Fri, 7 Dec 2018 06:45:33 +0530 Subject: [PATCH 18/37] minor scrolling fix and ellipsize fix --- .../android/support/design/widget/FlingBehavior.java | 3 +++ .../info_list/holder/CommentsMiniInfoItemHolder.java | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/android/support/design/widget/FlingBehavior.java b/app/src/main/java/android/support/design/widget/FlingBehavior.java index a453d302b..59eb08294 100644 --- a/app/src/main/java/android/support/design/widget/FlingBehavior.java +++ b/app/src/main/java/android/support/design/widget/FlingBehavior.java @@ -30,6 +30,9 @@ public final class FlingBehavior extends AppBarLayout.Behavior { // We're scrolling down } else { // We're scrolling up + if (mOffsetAnimator != null && mOffsetAnimator.isRunning()) { + mOffsetAnimator.cancel(); + } min = -child.getUpNestedPreScrollRange(); max = 0; consumed[1] = scroll(coordinatorLayout, child, dy, min, max); diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java index 046cadc3f..bf63c7c2d 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java @@ -1,7 +1,10 @@ package org.schabi.newpipe.info_list.holder; import android.support.v7.app.AppCompatActivity; +import android.text.SpannableString; import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.text.util.Linkify; import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -15,6 +18,7 @@ import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; +import org.schabi.newpipe.views.TouchTextView; import de.hdodenhof.circleimageview.CircleImageView; @@ -31,9 +35,9 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder { super(infoItemBuilder, layoutId, parent); itemThumbnailView = itemView.findViewById(R.id.itemThumbnailView); - itemContentView = itemView.findViewById(R.id.itemCommentContentView); itemLikesCountView = itemView.findViewById(R.id.detail_thumbs_up_count_view); itemDislikesCountView = itemView.findViewById(R.id.detail_thumbs_down_count_view); + itemContentView = itemView.findViewById(R.id.itemCommentContentView); } public CommentsMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) { @@ -66,6 +70,12 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder { } }); + // ellipsize if not already ellipsized + if (null == itemContentView.getEllipsize()) { + itemContentView.setEllipsize(TextUtils.TruncateAt.END); + itemContentView.setMaxLines(commentDefaultLines); + } + itemContentView.setText(item.getCommentText()); if (null != item.getLikeCount()) { itemLikesCountView.setText(String.valueOf(item.getLikeCount())); From ccb9bceecc8860554fb508503d6bcf29c168e107 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Fri, 7 Dec 2018 08:42:05 +0530 Subject: [PATCH 19/37] removed unused imports --- .../info_list/holder/CommentsMiniInfoItemHolder.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java index bf63c7c2d..966564221 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java @@ -1,11 +1,7 @@ package org.schabi.newpipe.info_list.holder; import android.support.v7.app.AppCompatActivity; -import android.text.SpannableString; import android.text.TextUtils; -import android.text.method.LinkMovementMethod; -import android.text.util.Linkify; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; @@ -16,9 +12,7 @@ import org.schabi.newpipe.extractor.comments.CommentsInfoItem; import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.util.ImageDisplayConstants; -import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; -import org.schabi.newpipe.views.TouchTextView; import de.hdodenhof.circleimageview.CircleImageView; From 1a62b9a161865bc47bb61c15f5af3e955b1d1144 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Sat, 8 Dec 2018 20:32:28 +0530 Subject: [PATCH 20/37] removed dislike button, added comment published time --- .../holder/CommentsMiniInfoItemHolder.java | 3 ++ .../main/res/layout/list_comments_item.xml | 31 ++++++------ .../res/layout/list_comments_mini_item.xml | 47 +++++++------------ 3 files changed, 36 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java index 966564221..c2bc86691 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java @@ -21,6 +21,7 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder { private final TextView itemContentView; private final TextView itemLikesCountView; private final TextView itemDislikesCountView; + private final TextView itemPublishedTime; private static final int commentDefaultLines = 2; private static final int commentExpandedLines = 1000; @@ -31,6 +32,7 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder { itemThumbnailView = itemView.findViewById(R.id.itemThumbnailView); itemLikesCountView = itemView.findViewById(R.id.detail_thumbs_up_count_view); itemDislikesCountView = itemView.findViewById(R.id.detail_thumbs_down_count_view); + itemPublishedTime = itemView.findViewById(R.id.itemPublishedTime); itemContentView = itemView.findViewById(R.id.itemCommentContentView); } @@ -74,6 +76,7 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder { if (null != item.getLikeCount()) { itemLikesCountView.setText(String.valueOf(item.getLikeCount())); } + itemPublishedTime.setText(item.getPublishedTime()); itemView.setOnClickListener(view -> { toggleEllipsize(item.getCommentText()); diff --git a/app/src/main/res/layout/list_comments_item.xml b/app/src/main/res/layout/list_comments_item.xml index 16b6107c5..a9b091329 100644 --- a/app/src/main/res/layout/list_comments_item.xml +++ b/app/src/main/res/layout/list_comments_item.xml @@ -49,17 +49,6 @@ android:textSize="@dimen/video_item_search_uploader_text_size" tools:text="Comment Content, Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blanditLorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blanditLorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blandit" /> - - + + + + diff --git a/app/src/main/res/layout/list_comments_mini_item.xml b/app/src/main/res/layout/list_comments_mini_item.xml index 7e8ce1a87..36f3e2e6e 100644 --- a/app/src/main/res/layout/list_comments_mini_item.xml +++ b/app/src/main/res/layout/list_comments_mini_item.xml @@ -20,27 +20,11 @@ android:src="@drawable/buddy_channel_item" tools:ignore="RtlHardcoded"/> - - - - - + + + + From 222c8fdb622fee18cccb6f8bb430fecb6329e226 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Sun, 9 Dec 2018 03:21:55 +0530 Subject: [PATCH 21/37] tablet ui support for comments --- .../fragments/detail/VideoDetailFragment.java | 64 ++-- .../list/comments/CommentsFragment.java | 5 + .../list/videos/RelatedVideosFragment.java | 5 + .../fragment_video_detail.xml | 273 +++++++++--------- 4 files changed, 186 insertions(+), 161 deletions(-) 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 3d5ac2d14..9a0c3b1b0 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 @@ -16,6 +16,7 @@ import android.support.annotation.Nullable; import android.support.design.widget.AppBarLayout; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewPager; import android.support.v4.view.animation.FastOutSlowInInterpolator; @@ -152,7 +153,6 @@ public class VideoDetailFragment private View videoTitleRoot; private TextView videoTitleTextView; - @Nullable private ImageView videoTitleToggleArrow; private TextView videoCountView; @@ -184,6 +184,7 @@ public class VideoDetailFragment private ViewPager viewPager; private TabAdaptor pageAdapter; private TabLayout tabLayout; + private FrameLayout relatedStreamsLayout; /*////////////////////////////////////////////////////////////////////////*/ @@ -419,16 +420,14 @@ public class VideoDetailFragment } private void toggleTitleAndDescription() { - if (videoTitleToggleArrow != null) { //it is null for tablets - if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) { - videoTitleTextView.setMaxLines(1); - videoDescriptionRootLayout.setVisibility(View.GONE); - videoTitleToggleArrow.setImageResource(R.drawable.arrow_down); - } else { - videoTitleTextView.setMaxLines(10); - videoDescriptionRootLayout.setVisibility(View.VISIBLE); - videoTitleToggleArrow.setImageResource(R.drawable.arrow_up); - } + if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) { + videoTitleTextView.setMaxLines(1); + videoDescriptionRootLayout.setVisibility(View.GONE); + videoTitleToggleArrow.setImageResource(R.drawable.arrow_down); + } else { + videoTitleTextView.setMaxLines(10); + videoDescriptionRootLayout.setVisibility(View.VISIBLE); + videoTitleToggleArrow.setImageResource(R.drawable.arrow_up); } } @@ -483,6 +482,8 @@ public class VideoDetailFragment tabLayout = rootView.findViewById(R.id.tablayout); tabLayout.setupWithViewPager(viewPager); + relatedStreamsLayout = rootView.findViewById(R.id.relatedStreamsLayout); + setHeightThumbnail(); @@ -809,7 +810,7 @@ public class VideoDetailFragment pageAdapter.addFragment(CommentsFragment.getInstance(serviceId, url, name), COMMENTS_TAB_TAG); } - if(showRelatedStreams){ + if(showRelatedStreams && null == relatedStreamsLayout){ //temp empty fragment. will be updated in handleResult pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG); } @@ -1033,14 +1034,18 @@ public class VideoDetailFragment animateView(videoTitleTextView, true, 0); videoDescriptionRootLayout.setVisibility(View.GONE); - if (videoTitleToggleArrow != null) { //phone - videoTitleToggleArrow.setImageResource(R.drawable.arrow_down); - videoTitleToggleArrow.setVisibility(View.GONE); - } else { //tablet - //TODO make comments/related streams fragment invisible - } + videoTitleToggleArrow.setImageResource(R.drawable.arrow_down); + videoTitleToggleArrow.setVisibility(View.GONE); videoTitleRoot.setClickable(false); + if(relatedStreamsLayout != null){ + if(showRelatedStreams){ + relatedStreamsLayout.setVisibility(View.INVISIBLE); + }else{ + relatedStreamsLayout.setVisibility(View.GONE); + } + } + imageLoader.cancelDisplayTask(thumbnailImageView); imageLoader.cancelDisplayTask(uploaderThumb); thumbnailImageView.setImageBitmap(null); @@ -1054,8 +1059,15 @@ public class VideoDetailFragment setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName()); if(showRelatedStreams){ - pageAdapter.updateItem(RELATED_TAB_TAG, RelatedVideosFragment.getInstance(currentInfo)); - pageAdapter.notifyDataSetUpdate(); + if(null == relatedStreamsLayout){ //phone + pageAdapter.updateItem(RELATED_TAB_TAG, RelatedVideosFragment.getInstance(currentInfo)); + pageAdapter.notifyDataSetUpdate(); + }else{ //tablet + getChildFragmentManager().beginTransaction() + .replace(R.id.relatedStreamsLayout, RelatedVideosFragment.getInstance(currentInfo)) + .commitNow(); + relatedStreamsLayout.setVisibility(View.VISIBLE); + } } pushToStack(serviceId, url, name); @@ -1120,14 +1132,10 @@ public class VideoDetailFragment } videoDescriptionView.setVisibility(View.GONE); - if (videoTitleToggleArrow != null) { - videoTitleRoot.setClickable(true); - videoTitleToggleArrow.setVisibility(View.VISIBLE); - videoTitleToggleArrow.setImageResource(R.drawable.arrow_down); - videoDescriptionRootLayout.setVisibility(View.GONE); - } else { - videoDescriptionRootLayout.setVisibility(View.VISIBLE); - } + videoTitleRoot.setClickable(true); + videoTitleToggleArrow.setVisibility(View.VISIBLE); + videoTitleToggleArrow.setImageResource(R.drawable.arrow_down); + videoDescriptionRootLayout.setVisibility(View.GONE); if (!TextUtils.isEmpty(info.getUploadDate())) { videoUploadDateView.setText(Localization.localizeDate(activity, info.getUploadDate())); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java index e7778c905..21d01be16 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java @@ -184,4 +184,9 @@ public class CommentsFragment extends BaseListInfoFragment { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { return; } + + @Override + protected boolean isGridLayout() { + return false; + } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java index 694731c69..5675bb81b 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java @@ -193,4 +193,9 @@ public class RelatedVideosFragment extends BaseListInfoFragment - + android:layout_height="match_parent" + android:layout_weight="5" + android:fitsSystemWindows="true"> - - + android:fitsSystemWindows="true" + app:elevation="0dp" + app:layout_behavior="android.support.design.widget.FlingBehavior"> - - + app:layout_scrollFlags="scroll"> - + + android:background="@android:color/black" + android:clickable="true" + android:focusable="true" + android:foreground="?attr/selectableItemBackground" + app:layout_collapseMode="parallax"> - + - + - - + + + + + + + android:layout_height="wrap_content" + android:background="?android:windowBackground" + app:layout_scrollFlags="scroll"> @@ -126,6 +140,15 @@ tools:ignore="RtlHardcoded" tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a ultricies ex. Integer sit amet sodales risus. Duis non mi et urna pretium bibendum. Nunc eleifend est quis ipsum porttitor egestas. Sed facilisis, nisl quis eleifend pellentesque, orci metus egestas dolor, at accumsan eros metus quis libero." /> + + @@ -209,17 +232,17 @@ tools:text="Uploader" /> + android:id="@+id/detail_uploader_subscribe" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical|right" + android:layout_marginRight="12dp" + android:text="@string/rss_button_title" + android:textSize="12sp" + android:theme="@style/RedButton" + android:drawableLeft="@drawable/ic_rss_feed_white_24dp" + tools:ignore="RtlHardcoded" + android:visibility="gone"/>--> @@ -401,7 +424,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" - android:orientation="vertical"> + android:orientation="vertical" + android:visibility="gone" + tools:visibility="visible"> + - - + - + + + + + + + + + - - - - - - - - - - + From 48067e3285f3ee424885500bff1be1976791d497 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Mon, 17 Dec 2018 10:03:04 +0530 Subject: [PATCH 22/37] up next text alignment --- app/src/main/res/layout/related_streams_header.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/res/layout/related_streams_header.xml b/app/src/main/res/layout/related_streams_header.xml index 5be7c928d..b98244b7e 100644 --- a/app/src/main/res/layout/related_streams_header.xml +++ b/app/src/main/res/layout/related_streams_header.xml @@ -11,7 +11,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="12dp" - android:layout_marginTop="5dp" + android:layout_alignBaseline="@+id/autoplay_switch" android:text="@string/next_video_title" android:textAppearance="?android:attr/textAppearanceMedium" android:textSize="12sp" @@ -22,7 +22,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" - android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:paddingRight="5dp" android:switchPadding="5dp" From ceaacc771d45dce82408688d7c5aaf3ea962ef54 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Wed, 19 Dec 2018 10:58:59 +0530 Subject: [PATCH 23/37] removed jerky animations --- .../fragments/detail/VideoDetailFragment.java | 44 +++-------------- .../list/comments/CommentsFragment.java | 47 ------------------- 2 files changed, 6 insertions(+), 85 deletions(-) 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 9a0c3b1b0..c8e8a387b 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 @@ -16,10 +16,8 @@ import android.support.annotation.Nullable; import android.support.design.widget.AppBarLayout; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentTransaction; import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewPager; -import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.support.v7.app.ActionBar; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; @@ -767,11 +765,9 @@ public class VideoDetailFragment initTabs(); if (scrollToTop) appBarLayout.setExpanded(true, true); - animateView(contentRootLayoutHiding, - false, 0, 0, () -> { - handleResult(info); - showContentWithAnimation(120, 0, .01f); - }); + handleResult(info); + showContent(); + } protected void prepareAndLoadInfo() { @@ -794,8 +790,8 @@ public class VideoDetailFragment .subscribe((@NonNull StreamInfo result) -> { isLoading.set(false); currentInfo = result; - showContentWithAnimation(120, 0, 0); handleResult(result); + showContent(); }, (@NonNull Throwable throwable) -> { isLoading.set(false); onError(throwable); @@ -960,36 +956,8 @@ public class VideoDetailFragment thumbnailImageView.setMinimumHeight(height); } - private void showContentWithAnimation(long duration, - long delay, - @FloatRange(from = 0.0f, to = 1.0f) float translationPercent) { - int translationY = (int) (getResources().getDisplayMetrics().heightPixels * - (translationPercent > 0.0f ? translationPercent : .06f)); - - contentRootLayoutHiding.animate().setListener(null).cancel(); - contentRootLayoutHiding.setAlpha(0f); - contentRootLayoutHiding.setTranslationY(translationY); + private void showContent() { contentRootLayoutHiding.setVisibility(View.VISIBLE); - contentRootLayoutHiding.animate() - .alpha(1f) - .translationY(0) - .setStartDelay(delay) - .setDuration(duration) - .setInterpolator(new FastOutSlowInInterpolator()) - .start(); - - uploaderRootLayout.animate().setListener(null).cancel(); - uploaderRootLayout.setAlpha(0f); - uploaderRootLayout.setTranslationY(translationY); - uploaderRootLayout.setVisibility(View.VISIBLE); - uploaderRootLayout.animate() - .alpha(1f) - .translationY(0) - .setStartDelay((long) (duration * .5f) + delay) - .setDuration(duration) - .setInterpolator(new FastOutSlowInInterpolator()) - .start(); - } protected void setInitialData(int serviceId, String url, String name) { @@ -1024,7 +992,7 @@ public class VideoDetailFragment public void showLoading() { super.showLoading(); - animateView(contentRootLayoutHiding, false, 200); + contentRootLayoutHiding.setVisibility(View.INVISIBLE); animateView(spinnerToolbar, false, 200); animateView(thumbnailPlayButton, false, 50); animateView(detailDurationView, false, 100); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java index 21d01be16..c930888f2 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java @@ -1,72 +1,25 @@ package org.schabi.newpipe.fragments.list.comments; -import android.app.Activity; import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.ActionBar; -import android.text.TextUtils; -import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; -import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.jakewharton.rxbinding2.view.RxView; import org.schabi.newpipe.R; -import org.schabi.newpipe.database.subscription.SubscriptionEntity; -import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.comments.CommentsInfo; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.extractor.stream.StreamInfoItem; -import org.schabi.newpipe.fragments.detail.VideoDetailFragment; import org.schabi.newpipe.fragments.list.BaseListInfoFragment; -import org.schabi.newpipe.info_list.InfoItemDialog; -import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; -import org.schabi.newpipe.local.subscription.SubscriptionService; -import org.schabi.newpipe.player.playqueue.ChannelPlayQueue; -import org.schabi.newpipe.player.playqueue.PlayQueue; -import org.schabi.newpipe.player.playqueue.SinglePlayQueue; import org.schabi.newpipe.report.UserAction; -import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.ExtractorHelper; -import org.schabi.newpipe.util.ImageDisplayConstants; -import org.schabi.newpipe.util.Localization; -import org.schabi.newpipe.util.NavigationHelper; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import io.reactivex.Observable; import io.reactivex.Single; -import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.disposables.Disposable; -import io.reactivex.functions.Action; -import io.reactivex.functions.Consumer; -import io.reactivex.functions.Function; -import io.reactivex.schedulers.Schedulers; - -import static org.schabi.newpipe.util.AnimationUtils.animateBackgroundColor; -import static org.schabi.newpipe.util.AnimationUtils.animateTextColor; -import static org.schabi.newpipe.util.AnimationUtils.animateView; public class CommentsFragment extends BaseListInfoFragment { From 990c220fa07bd328e28143dbee4138678392fbf2 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Sun, 23 Dec 2018 09:44:42 +0530 Subject: [PATCH 24/37] updated extractor --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index b34970907..c340595e1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -54,7 +54,7 @@ dependencies { exclude module: 'support-annotations' }) - implementation 'com.github.yausername:NewPipeExtractor:4c49a34' + implementation 'com.github.yausername:NewPipeExtractor:c77050d' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.23.0' From c9b938ae55473af6aa5749bef5e77d97672531e6 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Tue, 25 Dec 2018 15:36:15 +0530 Subject: [PATCH 25/37] readded animations --- .../fragments/detail/VideoDetailFragment.java | 3 ++- .../list/comments/CommentsFragment.java | 4 ++++ .../list/videos/RelatedVideosFragment.java | 7 +++++++ .../schabi/newpipe/util/AnimationUtils.java | 21 +++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) 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 7a821f548..c007789e5 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 @@ -75,6 +75,7 @@ import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ImageDisplayConstants; @@ -956,7 +957,7 @@ public class VideoDetailFragment } private void showContent() { - contentRootLayoutHiding.setVisibility(View.VISIBLE); + AnimationUtils.slideUp(contentRootLayoutHiding,120, 96, 0.06f); } protected void setInitialData(int serviceId, String url, String name) { diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java index c930888f2..956e6c1c8 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java @@ -16,6 +16,7 @@ import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.comments.CommentsInfo; import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.ExtractorHelper; import io.reactivex.Single; @@ -92,6 +93,8 @@ public class CommentsFragment extends BaseListInfoFragment { public void handleResult(@NonNull CommentsInfo result) { super.handleResult(result); + AnimationUtils.slideUp(getView(),120, 96, 0.06f); + if (!result.getErrors().isEmpty()) { showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); } @@ -120,6 +123,7 @@ public class CommentsFragment extends BaseListInfoFragment { protected boolean onError(Throwable exception) { if (super.onError(exception)) return true; + hideLoading(); showSnackBarError(exception, UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(serviceId), url, R.string.error_unable_to_load_comments); return true; } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java index 5675bb81b..c8fc2197a 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java @@ -20,6 +20,7 @@ import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.RelatedStreamInfo; import java.io.Serializable; @@ -110,12 +111,17 @@ public class RelatedVideosFragment extends BaseListInfoFragment Date: Tue, 25 Dec 2018 19:59:03 +0530 Subject: [PATCH 26/37] fixed NPE in soundcloud --- .../newpipe/fragments/list/videos/RelatedVideosFragment.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java index c8fc2197a..702e0e3fb 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java @@ -111,7 +111,7 @@ public class RelatedVideosFragment extends BaseListInfoFragment Date: Tue, 25 Dec 2018 20:17:56 +0530 Subject: [PATCH 27/37] more NPE fix --- .../newpipe/fragments/list/videos/RelatedVideosFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java index 702e0e3fb..69a59c2f1 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/videos/RelatedVideosFragment.java @@ -198,7 +198,7 @@ public class RelatedVideosFragment extends BaseListInfoFragment Date: Sat, 19 Jan 2019 15:26:31 +0530 Subject: [PATCH 28/37] updated extractor for url decryption fix --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index c340595e1..3c80c6e7e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -54,7 +54,7 @@ dependencies { exclude module: 'support-annotations' }) - implementation 'com.github.yausername:NewPipeExtractor:c77050d' + implementation 'com.github.yausername:NewPipeExtractor:25ed9de' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.23.0' From ed4b4a1a3ca0ccf570d275a07ced98555cd32105 Mon Sep 17 00:00:00 2001 From: Alec Holmes Date: Fri, 1 Feb 2019 13:02:28 +0000 Subject: [PATCH 29/37] Updated search fragment to be amazon fire tv friendly --- .../java/org/schabi/newpipe/firetv/FireTvUtils.java | 11 +++++++++++ .../fragments/list/search/SearchFragment.java | 13 +++++++++---- app/src/main/res/layout/toolbar_search_layout.xml | 4 +++- 3 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/firetv/FireTvUtils.java diff --git a/app/src/main/java/org/schabi/newpipe/firetv/FireTvUtils.java b/app/src/main/java/org/schabi/newpipe/firetv/FireTvUtils.java new file mode 100644 index 000000000..305c29ee7 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/firetv/FireTvUtils.java @@ -0,0 +1,11 @@ +package org.schabi.newpipe.firetv; + +import android.content.Context; +import org.schabi.newpipe.App; + +public class FireTvUtils { + public static boolean isFireTv(){ + final String AMAZON_FEATURE_FIRE_TV = "amazon.hardware.fire_tv"; + return App.getApp().getPackageManager().hasSystemFeature(AMAZON_FEATURE_FIRE_TV); + } +} 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 2833abb8d..0e8aad01d 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 @@ -39,6 +39,7 @@ import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.search.SearchExtractor; import org.schabi.newpipe.extractor.search.SearchInfo; +import org.schabi.newpipe.firetv.FireTvUtils; import org.schabi.newpipe.fragments.BackPressable; import org.schabi.newpipe.fragments.list.BaseListFragment; import org.schabi.newpipe.local.history.HistoryRecordManager; @@ -449,6 +450,9 @@ public class SearchFragment if (isSuggestionsEnabled && errorPanelRoot.getVisibility() != View.VISIBLE) { showSuggestionsPanel(); } + if(FireTvUtils.isFireTv()){ + showKeyboardSearch(); + } }); searchEditText.setOnFocusChangeListener((View v, boolean hasFocus) -> { @@ -499,7 +503,9 @@ public class SearchFragment if (DEBUG) { Log.d(TAG, "onEditorAction() called with: v = [" + v + "], actionId = [" + actionId + "], event = [" + event + "]"); } - if (event != null + if(actionId == EditorInfo.IME_ACTION_PREVIOUS){ + hideKeyboardSearch(); + } else if (event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER || event.getAction() == EditorInfo.IME_ACTION_SEARCH)) { search(searchEditText.getText().toString(), new String[0], ""); @@ -541,7 +547,7 @@ public class SearchFragment if (searchEditText.requestFocus()) { InputMethodManager imm = (InputMethodManager) activity.getSystemService( Context.INPUT_METHOD_SERVICE); - imm.showSoftInput(searchEditText, InputMethodManager.SHOW_IMPLICIT); + imm.showSoftInput(searchEditText, InputMethodManager.SHOW_FORCED); } } @@ -551,8 +557,7 @@ public class SearchFragment InputMethodManager imm = (InputMethodManager) activity.getSystemService( Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(searchEditText.getWindowToken(), - InputMethodManager.HIDE_NOT_ALWAYS); + imm.hideSoftInputFromWindow(searchEditText.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN); searchEditText.clearFocus(); } diff --git a/app/src/main/res/layout/toolbar_search_layout.xml b/app/src/main/res/layout/toolbar_search_layout.xml index 797eea48e..9e9e51442 100644 --- a/app/src/main/res/layout/toolbar_search_layout.xml +++ b/app/src/main/res/layout/toolbar_search_layout.xml @@ -30,7 +30,9 @@ android:layout_width="48dp" android:layout_height="48dp" android:layout_gravity="right|center_vertical" - tools:ignore="RtlHardcoded"> + android:focusable="true" + tools:ignore="RtlHardcoded" + android:background="?attr/selectableItemBackground"> Date: Sat, 9 Feb 2019 12:30:14 +0100 Subject: [PATCH 30/37] added support for youtube-nocookie.com --- app/src/main/AndroidManifest.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 06d621016..db2d5f13c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -183,6 +183,19 @@ + + + + + + + + + + + + + From 9437f057d0e2a5f242cf8aae9ce5376c8b3b4f72 Mon Sep 17 00:00:00 2001 From: Redirion Date: Thu, 14 Feb 2019 09:52:46 +0100 Subject: [PATCH 31/37] Fix delayed ducking of Audio Scenario: listening to a video on NewPipe over Bluetooth and a Notification Sound causes audio focus event AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK. Problem: With the current implementation animateAudio would cause the audio to reach the target volume AFTER the notification sound is played, which is irritating and annoying. Solution: animateAudio should just be used on focusGain where it is sensible to increase audio gradually. On ducking event the reaction should be immediate. This very simple fix does this. Please approve. --- .../java/org/schabi/newpipe/player/helper/AudioReactor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java b/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java index 46d20c7e1..f148aed27 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java @@ -131,7 +131,7 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, private void onAudioFocusLossCanDuck() { Log.d(TAG, "onAudioFocusLossCanDuck() called"); // Set the volume to 1/10 on ducking - animateAudio(player.getVolume(), DUCK_AUDIO_TO); + player.setVolume(DUCK_AUDIO_TO); } private void animateAudio(final float from, final float to) { From 56cb8209b8ec8ba1d2d8fef0955ee2359347b3df Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Sat, 16 Feb 2019 01:23:26 +0530 Subject: [PATCH 32/37] refactored comments capability --- app/build.gradle | 2 +- .../newpipe/fragments/detail/VideoDetailFragment.java | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f47db03d0..f135bb017 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -57,7 +57,7 @@ dependencies { exclude module: 'support-annotations' }) - implementation 'com.github.yausername:NewPipeExtractor:f97d5ab' + implementation 'com.github.yausername:NewPipeExtractor:3dadf63' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.23.0' 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 c007789e5..63f4fc722 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 @@ -100,6 +100,7 @@ import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS; import static org.schabi.newpipe.util.AnimationUtils.animateView; public class VideoDetailFragment @@ -822,7 +823,10 @@ public class VideoDetailFragment private boolean shouldShowComments() { try { - return showComments && NewPipe.getService(serviceId).isCommentsSupported(); + return showComments && NewPipe.getService(serviceId) + .getServiceInfo() + .getMediaCapabilities() + .contains(COMMENTS); } catch (ExtractionException e) { return false; } From db9cf9564820fbf1bbd6087d3e6b3189d69d2e13 Mon Sep 17 00:00:00 2001 From: TobiGr Date: Sun, 17 Feb 2019 09:52:05 +0100 Subject: [PATCH 33/37] Remove old player from the manifest See https://github.com/TeamNewPipe/NewPipe/pull/1884 for more info --- app/src/main/AndroidManifest.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 06d621016..af6dda798 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -35,12 +35,6 @@ - - From 4dd572063ef5b38d9c31e66b306e47727702e106 Mon Sep 17 00:00:00 2001 From: kapodamy Date: Sun, 17 Feb 2019 16:59:35 -0300 Subject: [PATCH 34/37] fix crash while switching from popup to fullscreen player, or closing the popup player. --- .../main/java/org/schabi/newpipe/player/PopupVideoPlayer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index f5c731ed9..8ea3d509c 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -626,6 +626,7 @@ public final class PopupVideoPlayer extends Service { @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { super.onLoadingComplete(imageUri, view, loadedImage); + if (playerImpl == null) return; // rebuild notification here since remote view does not release bitmaps, // causing memory leaks resetNotification(); From 4b5591d8844a3255e3e83eada605cd3b4b781f29 Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Tue, 19 Feb 2019 14:57:49 +0100 Subject: [PATCH 35/37] move firetv utils into utils package --- .../schabi/newpipe/fragments/list/search/SearchFragment.java | 2 +- .../java/org/schabi/newpipe/{firetv => util}/FireTvUtils.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) rename app/src/main/java/org/schabi/newpipe/{firetv => util}/FireTvUtils.java (80%) 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 87ebf14d2..e20d6bad3 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 @@ -39,7 +39,7 @@ import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.search.SearchExtractor; import org.schabi.newpipe.extractor.search.SearchInfo; -import org.schabi.newpipe.firetv.FireTvUtils; +import org.schabi.newpipe.util.FireTvUtils; import org.schabi.newpipe.fragments.BackPressable; import org.schabi.newpipe.fragments.list.BaseListFragment; import org.schabi.newpipe.local.history.HistoryRecordManager; diff --git a/app/src/main/java/org/schabi/newpipe/firetv/FireTvUtils.java b/app/src/main/java/org/schabi/newpipe/util/FireTvUtils.java similarity index 80% rename from app/src/main/java/org/schabi/newpipe/firetv/FireTvUtils.java rename to app/src/main/java/org/schabi/newpipe/util/FireTvUtils.java index 305c29ee7..69666463e 100644 --- a/app/src/main/java/org/schabi/newpipe/firetv/FireTvUtils.java +++ b/app/src/main/java/org/schabi/newpipe/util/FireTvUtils.java @@ -1,6 +1,5 @@ -package org.schabi.newpipe.firetv; +package org.schabi.newpipe.util; -import android.content.Context; import org.schabi.newpipe.App; public class FireTvUtils { From 7981f9dc9129f232d5dce75e7277d19f55316e40 Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Tue, 19 Feb 2019 16:03:10 +0100 Subject: [PATCH 36/37] add database doc in dia --- assets/db.dia | Bin 0 -> 2520 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/db.dia diff --git a/assets/db.dia b/assets/db.dia new file mode 100644 index 0000000000000000000000000000000000000000..59b090c882231a47746e961a41c36b1c82b238b0 GIT binary patch literal 2520 zcmV;}2`Ba+iwFP!000021MOYga;rENeLr8}@_9`Z?w3v{T{F`))elqERWoOvDH#-- zJ{UYgB*!oF?Je2l0vO)_cSx42asdl1NoYx%rM<<^zx-GxlSjt$I7{!QI?<*RmWEjr zr}Mk%f4}|n+ME7z|K;Z>ra#G_Ij75sydurj(cN?*#OkM;o2REIlB{zoGES1XAUV7F zKTQ&PBNN?B@4rkYZ!?Ifpz2(CmI}e+Ss~aYrAu} zyXn`5@-w|DGrFndv?uo!owFHd^m}{en*8|wd6};muV=hmWqB-yRP>hp zx}WUpJzz6Oyk6e1$8B?KorEHf*~~s?5}Frr#PS23xtgXWr$w3U=1{xW({*f`D9%?2 zUGJ|#JyA&tN?v;ipu&tJ|Dg5 z@Y_3AcI00r*i81%$@S!$x_J6(j!R=aj_#(vYgH=L+fQaE&4C7;H_cd%dKS?P+r4s# z>pQMhXKJ(6+F)k0Ito{HPUi{RiF9k2@*jDuo5YeQ&O=@@L8k{s=O~t3I4gISuw@Wt zJZ&20eK+9-YBR?+oAG&m^@;2FZ$C~4tObkb3(*edkSdmMo(EQYVyQf@C6c{;zFfMIt7OZ$IA0F1hcedUORvqw8!4h;X zpH1dNS80|d(c9YOLjk=U=Z6M`&1f9Fq;F0s2cNua-AfueEf3#&CcU=XB8#{WE6LJ% zZ(z-Pe;jqr!P?!UkDJC%M@x$&+02`Vpc-b^=~zV?|F2*ds8qxrXpx9OW>>I&Z`w|a z=yD9o8GnpJ7F>`>at{CSJnEryze6JRfOIsIuJzGzso=@QNc5l0U+@S#`e-wf`W`d_ zjX&o2-iK&a11sEEC2(3qaUrVq-dla_2U zzNAU;kTq8X)Vaw6UB=1!Zo16UEML)(O((fntHn)iT4wQ&tl%-@=Pwx@M$c)QzW{qL z$iK1Vk%>5@*MHBF=)3}yd^)uZ%_96hOEz8VrsHimxLT(XPpf{cj%|MgWNm@)+~vr( zt$jIE!G4H9`PCG>xmHwl`P8&mZ=2IVHp_TJgFM7Zas)`-Gxm&{99W;$h+gZ2`T?-* z$*t2v2QLV{s~3b}6W?~+E0<`tZ+QcHLDZ0LO;a*gcdvZno{#(o1e_p7>;zGEWw=7X6#}9}7b2~AHs>tQ0})?v z2?`P)*aT4mq69<sTaW zkst^IJOYn;S(;V3Uy@A{^IM;gU=$ejUL3~@PA}>;j^$Yp=|es!t&)sJjKj(Ul|ZF# zPfLqpIZJ7rAlepug69xChu}E`&mnjYjmvY$?Cd#298+`sE8QlJuDL^c4potEb)6WN z?Oo|U(a%PH7oJ0XG~qFxL!Qjv?jgeHD9<5t2+tw4*>)1=0&yL=H(0Gy;tfS_>9| zMObJ8pTH-?F@Z{;(x-@4#~aQ-COAOA0Rj#XaDadV#Hbt~?5++Fx=l>OHdO?Us}H&R zaTVy+Fo>mTrV3#)^bzlU+(-Kz_dX`g9e)7Rzv5g3rPcX|Y(%&`z~y1YE)UP1J9rfn zTp!^2(1Q{I9zlkHrq_u{%B%`vX;1vX&f=JnKHiK3IS+Cki4l`8k z1KSt?r}URM@8&yq&Qt<>z-bg0`JQT?sdlGPKsnEz+UsN(9kUJ+md^LzBD*WZ!A@`{ zLM|v5+W|3%SRS_N=-q{SRhPp!dS{%!+~hyW*0pOUpm!W-n5C(lily0*HwK^QZzcaBK5;b7Q%IUbx;5o&Y$|iWB(^zf zsi&<8+mlL5#P)pSKvLf^oRgB8#2QxYIns97cOC2+*fp?gKDb?@5u(Gi8NJ-2S4|tg zgW6;CZ56e7v-{m&$>BPdX-^-!gsfw zpS&y8nbYmx!98b`hl^kl=hEm|!?hi*?IU(=hbJ!l2jPg@g+Za5eUyn5L{waEH?m** z1cO^U*z}3_#{2|s?O@U;WRiMJ!R|>Q5;lB6ga{%;5FvsHk@0N!qHCR=Ezy(nI?lx8sZDjBSq>NZ^pbKa2#9Jt?4sLviSVNHh#t zoZ{6Ro7qJH{|`q6sa i<;6ca?q_?P&^6=tU$zJGXU^&J{>z`GBdjay_y7Pr;@O)3 literal 0 HcmV?d00001 From 841124b1f358b4808d19c804a42fd7ca6ea8c64b Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Wed, 20 Feb 2019 05:24:33 +0530 Subject: [PATCH 37/37] updated extractor, fixed settings padding --- app/build.gradle | 2 +- app/src/main/res/xml/content_settings.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index f135bb017..2d46fcc90 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -57,7 +57,7 @@ dependencies { exclude module: 'support-annotations' }) - implementation 'com.github.yausername:NewPipeExtractor:3dadf63' + implementation 'com.github.TeamNewPipe:NewPipeExtractor:8de53111d9' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.23.0' diff --git a/app/src/main/res/xml/content_settings.xml b/app/src/main/res/xml/content_settings.xml index d09b12456..1a1a39e21 100644 --- a/app/src/main/res/xml/content_settings.xml +++ b/app/src/main/res/xml/content_settings.xml @@ -42,6 +42,7 @@ android:summary="@string/download_thumbnail_summary"/>