From 0a831ec84e7a3c822ce1822d97bc9b934a510f33 Mon Sep 17 00:00:00 2001 From: TobiGr Date: Tue, 15 Dec 2020 17:41:21 +0100 Subject: [PATCH] Display meta info about search query, stream creator or topic Closes #4614 --- app/build.gradle | 2 +- .../newpipe/fragments/MainFragment.java | 2 +- .../fragments/detail/VideoDetailFragment.java | 77 +++++++++++++++---- .../fragments/list/search/SearchFragment.java | 48 ++++++++++++ .../fragment_video_detail.xml | 32 ++++++++ app/src/main/res/layout/fragment_search.xml | 14 +++- .../main/res/layout/fragment_video_detail.xml | 33 ++++++++ app/src/main/res/values/settings_keys.xml | 1 + app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/content_settings.xml | 7 ++ 10 files changed, 200 insertions(+), 18 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 15561b2d2..fadfc3221 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -179,7 +179,7 @@ dependencies { // NewPipe dependencies // You can use a local version by uncommenting a few lines in settings.gradle - implementation 'com.github.TeamNewPipe:NewPipeExtractor:85fa006214b003f21eacb76c445a167732f19981' + implementation 'com.github.TeamNewPipe:NewPipeExtractor:79b5aa9760da52020821b68e2af41a9238943304' implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751" implementation "org.jsoup:jsoup:1.13.1" diff --git a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java index 866b324ec..a77109f86 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/MainFragment.java @@ -3,7 +3,6 @@ package org.schabi.newpipe.fragments; import android.content.Context; import android.content.res.ColorStateList; import android.os.Bundle; -import androidx.preference.PreferenceManager; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -19,6 +18,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentStatePagerAdapterMenuWorkaround; +import androidx.preference.PreferenceManager; import androidx.viewpager.widget.ViewPager; import com.google.android.material.tabs.TabLayout; 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 427cff06e..b9cb4ab2b 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,7 +16,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.provider.Settings; -import android.text.TextUtils; +import android.text.method.LinkMovementMethod; import android.text.util.Linkify; import android.util.DisplayMetrics; import android.util.Log; @@ -63,6 +63,7 @@ import org.schabi.newpipe.R; import org.schabi.newpipe.ReCaptchaActivity; import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.extractor.InfoItem; +import org.schabi.newpipe.extractor.MetaInfo; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.exceptions.ExtractionException; @@ -122,8 +123,10 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.schedulers.Schedulers; +import static android.text.TextUtils.isEmpty; import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS; import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT; +import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked; import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired; import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET; @@ -218,6 +221,10 @@ public final class VideoDetailFragment private TextView detailDurationView; private TextView detailPositionView; + private LinearLayout detailMetadataInfo; + private View detailMetadataInfoSeparator; + private TextView detailMetadataInfoText; + private LinearLayout videoDescriptionRootLayout; private TextView videoUploadDateView; private TextView videoDescriptionView; @@ -508,8 +515,8 @@ public final class VideoDetailFragment } break; case R.id.detail_uploader_root_layout: - if (TextUtils.isEmpty(currentInfo.getSubChannelUrl())) { - if (!TextUtils.isEmpty(currentInfo.getUploaderUrl())) { + if (isEmpty(currentInfo.getSubChannelUrl())) { + if (!isEmpty(currentInfo.getUploaderUrl())) { openChannel(currentInfo.getUploaderUrl(), currentInfo.getUploaderName()); } @@ -583,7 +590,7 @@ public final class VideoDetailFragment } break; case R.id.detail_uploader_root_layout: - if (TextUtils.isEmpty(currentInfo.getSubChannelUrl())) { + if (isEmpty(currentInfo.getSubChannelUrl())) { Log.w(TAG, "Can't open parent channel because we got no parent channel URL"); } else { @@ -644,6 +651,10 @@ public final class VideoDetailFragment detailDurationView = rootView.findViewById(R.id.detail_duration_view); detailPositionView = rootView.findViewById(R.id.detail_position_view); + detailMetadataInfo = rootView.findViewById(R.id.detail_metadata_info); + detailMetadataInfoSeparator = rootView.findViewById(R.id.detail_metadata_info_separator); + detailMetadataInfoText = rootView.findViewById(R.id.detail_metadata_info_text); + videoDescriptionRootLayout = rootView.findViewById(R.id.detail_description_root_layout); videoUploadDateView = rootView.findViewById(R.id.detail_upload_date_view); videoDescriptionView = rootView.findViewById(R.id.detail_description_view); @@ -748,7 +759,7 @@ public final class VideoDetailFragment private void initThumbnailViews(@NonNull final StreamInfo info) { thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark); - if (!TextUtils.isEmpty(info.getThumbnailUrl())) { + if (!isEmpty(info.getThumbnailUrl())) { final String infoServiceName = NewPipe.getNameOfService(info.getServiceId()); final ImageLoadingListener onFailListener = new SimpleImageLoadingListener() { @Override @@ -763,12 +774,12 @@ public final class VideoDetailFragment ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, onFailListener); } - if (!TextUtils.isEmpty(info.getSubChannelAvatarUrl())) { + if (!isEmpty(info.getSubChannelAvatarUrl())) { IMAGE_LOADER.displayImage(info.getSubChannelAvatarUrl(), subChannelThumb, ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); } - if (!TextUtils.isEmpty(info.getUploaderAvatarUrl())) { + if (!isEmpty(info.getUploaderAvatarUrl())) { IMAGE_LOADER.displayImage(info.getUploaderAvatarUrl(), uploaderThumb, ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); } @@ -1217,7 +1228,7 @@ public final class VideoDetailFragment } private void prepareDescription(final Description description) { - if (description == null || TextUtils.isEmpty(description.getContent()) + if (description == null || isEmpty(description.getContent()) || description == Description.emptyDescription) { return; } @@ -1247,6 +1258,42 @@ public final class VideoDetailFragment } } + private void setMetaInfo(final StreamInfo info) { + final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences( + requireContext()); + final boolean showMetaInfo = sp.getBoolean( + requireContext().getString(R.string.show_meta_info_key), true); + if (info.getMetaInfo().isEmpty() || !showMetaInfo) { + detailMetadataInfo.setVisibility(View.GONE); + detailMetadataInfoSeparator.setVisibility(View.GONE); + } else { + final List metaIfs = info.getMetaInfo(); + final StringBuilder stringBuilder = new StringBuilder(); + for (final MetaInfo mi: metaIfs) { + if (!isNullOrEmpty(mi.getTitle())) { + stringBuilder.append("

").append(mi.getTitle()).append("

"); + } + stringBuilder.append(mi.getContent().getContent()); + for (int i = 0; i < mi.getUrls().size(); i++) { + stringBuilder + .append(" ") + .append(mi.getUrlTexts().get(i)) + .append(""); + if (i < mi.getUrls().size() - 1 && mi.getUrls().size() > 1) { + // append line break to all but the last URL if there are multiple URLs + stringBuilder.append("
"); + } + } + } + + detailMetadataInfoSeparator.setVisibility(View.VISIBLE); + detailMetadataInfoText.setText(HtmlCompat.fromHtml( + stringBuilder.toString(), HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING)); + detailMetadataInfoText.setMovementMethod(LinkMovementMethod.getInstance()); + detailMetadataInfo.setVisibility(View.VISIBLE); + } + } + private final ViewTreeObserver.OnPreDrawListener preDrawListener = new ViewTreeObserver.OnPreDrawListener() { @Override @@ -1462,9 +1509,9 @@ public final class VideoDetailFragment animateView(thumbnailPlayButton, true, 200); videoTitleTextView.setText(title); - if (!TextUtils.isEmpty(info.getSubChannelName())) { + if (!isEmpty(info.getSubChannelName())) { displayBothUploaderAndSubChannel(info); - } else if (!TextUtils.isEmpty(info.getUploaderName())) { + } else if (!isEmpty(info.getUploaderName())) { displayUploaderAsSubChannel(info); } else { uploaderTextView.setVisibility(View.GONE); @@ -1559,6 +1606,8 @@ public final class VideoDetailFragment prepareDescription(info.getDescription()); updateProgressInfo(info); initThumbnailViews(info); + setMetaInfo(info); + if (player == null || player.isPlayerStopped()) { updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl()); @@ -1610,7 +1659,7 @@ public final class VideoDetailFragment subChannelThumb.setVisibility(View.VISIBLE); - if (!TextUtils.isEmpty(info.getUploaderName())) { + if (!isEmpty(info.getUploaderName())) { uploaderTextView.setText( String.format(getString(R.string.video_detail_by), info.getUploaderName())); uploaderTextView.setVisibility(View.VISIBLE); @@ -2305,10 +2354,10 @@ public final class VideoDetailFragment private void updateOverlayData(@Nullable final String overlayTitle, @Nullable final String uploader, @Nullable final String thumbnailUrl) { - overlayTitleTextView.setText(TextUtils.isEmpty(overlayTitle) ? "" : overlayTitle); - overlayChannelTextView.setText(TextUtils.isEmpty(uploader) ? "" : uploader); + overlayTitleTextView.setText(isEmpty(title) ? "" : title); + overlayChannelTextView.setText(isEmpty(uploader) ? "" : uploader); overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark); - if (!TextUtils.isEmpty(thumbnailUrl)) { + if (!isEmpty(thumbnailUrl)) { IMAGE_LOADER.displayImage(thumbnailUrl, overlayThumbnailImageView, ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, null); } 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 02dbf176b..f44e5e330 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 @@ -9,6 +9,7 @@ import android.text.Editable; import android.text.Html; import android.text.TextUtils; import android.text.TextWatcher; +import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -39,6 +40,7 @@ import org.schabi.newpipe.ReCaptchaActivity; import org.schabi.newpipe.database.history.model.SearchHistoryEntry; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor; +import org.schabi.newpipe.extractor.MetaInfo; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.Page; import org.schabi.newpipe.extractor.StreamingService; @@ -78,6 +80,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject; import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags; import static java.util.Arrays.asList; +import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; import static org.schabi.newpipe.util.AnimationUtils.animateView; public class SearchFragment extends BaseListFragment> @@ -129,6 +132,9 @@ public class SearchFragment extends BaseListFragment cannot be bundled without creating some containers + metaInfo = new MetaInfo[result.getMetaInfo().size()]; + metaInfo = result.getMetaInfo().toArray(metaInfo); + handleSearchSuggestion(); + handleMetaInfo(); lastSearchedString = searchString; nextPage = result.getNextPage(); @@ -1021,6 +1036,39 @@ public class SearchFragment extends BaseListFragment").append(mi.getTitle()).append(""); + } + stringBuilder.append(mi.getContent().getContent()); + for (int i = 0; i < mi.getUrls().size(); i++) { + stringBuilder + .append(" ") + .append(mi.getUrlTexts().get(i)) + .append(""); + if (i < mi.getUrls().size() - 1 && mi.getUrls().size() > 1) { + // append line break to all but the last URL if there are multiple URLs + stringBuilder.append("
"); + } + } + } + + metaInfoTextView.setText(HtmlCompat.fromHtml( + stringBuilder.toString(), HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING)); + metaInfoTextView.setMovementMethod(LinkMovementMethod.getInstance()); + metaInfoTextView.setVisibility(View.VISIBLE); + } + } + @Override public void handleNextItems(final ListExtractor.InfoItemsPage result) { showListFooter(false); diff --git a/app/src/main/res/layout-large-land/fragment_video_detail.xml b/app/src/main/res/layout-large-land/fragment_video_detail.xml index 8aee89ab0..d59d2db73 100644 --- a/app/src/main/res/layout-large-land/fragment_video_detail.xml +++ b/app/src/main/res/layout-large-land/fragment_video_detail.xml @@ -506,6 +506,38 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml index 0df85fe95..3bf2bb025 100644 --- a/app/src/main/res/layout/fragment_video_detail.xml +++ b/app/src/main/res/layout/fragment_video_detail.xml @@ -491,6 +491,39 @@ + + + + + + + + + + show_play_with_kodi show_next_video show_comments + show_meta_info stream_info_selected_tab show_hold_to_append content_language diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ecb690044..d2dd8afd5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -93,6 +93,8 @@ Show comments Turn off to hide comments Turn off to prevent loading thumbnails, saving data and memory usage. Changes clear both in-memory and on-disk image cache. + Show meta info + Turn off to hide meta info boxes with additional information about the stream creator, stream content or a search request. 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 c885366ec..914fb2e59 100644 --- a/app/src/main/res/xml/content_settings.xml +++ b/app/src/main/res/xml/content_settings.xml @@ -85,6 +85,13 @@ android:title="@string/show_comments_title" app:iconSpaceReserved="false" /> + +