Merge pull request #4754 from TeamNewPipe/meta_info

Display meta info about search query, stream creator or topic
This commit is contained in:
Tobias Groza 2020-12-23 11:34:48 +01:00 committed by GitHub
commit 84d1792e7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 188 additions and 19 deletions

View file

@ -179,7 +179,7 @@ dependencies {
// NewPipe dependencies // NewPipe dependencies
// You can use a local version by uncommenting a few lines in settings.gradle // 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 "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751"
implementation "org.jsoup:jsoup:1.13.1" implementation "org.jsoup:jsoup:1.13.1"

View file

@ -3,7 +3,6 @@ package org.schabi.newpipe.fragments;
import android.content.Context; import android.content.Context;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.os.Bundle; import android.os.Bundle;
import androidx.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@ -19,6 +18,7 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapterMenuWorkaround; import androidx.fragment.app.FragmentStatePagerAdapterMenuWorkaround;
import androidx.preference.PreferenceManager;
import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayout;

View file

@ -16,7 +16,6 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.provider.Settings; import android.provider.Settings;
import android.text.TextUtils;
import android.text.util.Linkify; import android.text.util.Linkify;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
@ -122,12 +121,14 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers; 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.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT; import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked; import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired; import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET; import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
import static org.schabi.newpipe.util.AnimationUtils.animateView; import static org.schabi.newpipe.util.AnimationUtils.animateView;
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
public final class VideoDetailFragment public final class VideoDetailFragment
extends BaseStateFragment<StreamInfo> extends BaseStateFragment<StreamInfo>
@ -218,6 +219,9 @@ public final class VideoDetailFragment
private TextView detailDurationView; private TextView detailDurationView;
private TextView detailPositionView; private TextView detailPositionView;
private View detailMetaInfoSeparator;
private TextView detailMetaInfoTextView;
private LinearLayout videoDescriptionRootLayout; private LinearLayout videoDescriptionRootLayout;
private TextView videoUploadDateView; private TextView videoUploadDateView;
private TextView videoDescriptionView; private TextView videoDescriptionView;
@ -508,8 +512,8 @@ public final class VideoDetailFragment
} }
break; break;
case R.id.detail_uploader_root_layout: case R.id.detail_uploader_root_layout:
if (TextUtils.isEmpty(currentInfo.getSubChannelUrl())) { if (isEmpty(currentInfo.getSubChannelUrl())) {
if (!TextUtils.isEmpty(currentInfo.getUploaderUrl())) { if (!isEmpty(currentInfo.getUploaderUrl())) {
openChannel(currentInfo.getUploaderUrl(), currentInfo.getUploaderName()); openChannel(currentInfo.getUploaderUrl(), currentInfo.getUploaderName());
} }
@ -583,7 +587,7 @@ public final class VideoDetailFragment
} }
break; break;
case R.id.detail_uploader_root_layout: case R.id.detail_uploader_root_layout:
if (TextUtils.isEmpty(currentInfo.getSubChannelUrl())) { if (isEmpty(currentInfo.getSubChannelUrl())) {
Log.w(TAG, Log.w(TAG,
"Can't open parent channel because we got no parent channel URL"); "Can't open parent channel because we got no parent channel URL");
} else { } else {
@ -644,6 +648,9 @@ public final class VideoDetailFragment
detailDurationView = rootView.findViewById(R.id.detail_duration_view); detailDurationView = rootView.findViewById(R.id.detail_duration_view);
detailPositionView = rootView.findViewById(R.id.detail_position_view); detailPositionView = rootView.findViewById(R.id.detail_position_view);
detailMetaInfoSeparator = rootView.findViewById(R.id.detail_meta_info_separator);
detailMetaInfoTextView = rootView.findViewById(R.id.detail_meta_info_text_view);
videoDescriptionRootLayout = rootView.findViewById(R.id.detail_description_root_layout); videoDescriptionRootLayout = rootView.findViewById(R.id.detail_description_root_layout);
videoUploadDateView = rootView.findViewById(R.id.detail_upload_date_view); videoUploadDateView = rootView.findViewById(R.id.detail_upload_date_view);
videoDescriptionView = rootView.findViewById(R.id.detail_description_view); videoDescriptionView = rootView.findViewById(R.id.detail_description_view);
@ -748,7 +755,7 @@ public final class VideoDetailFragment
private void initThumbnailViews(@NonNull final StreamInfo info) { private void initThumbnailViews(@NonNull final StreamInfo info) {
thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark); thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
if (!TextUtils.isEmpty(info.getThumbnailUrl())) { if (!isEmpty(info.getThumbnailUrl())) {
final String infoServiceName = NewPipe.getNameOfService(info.getServiceId()); final String infoServiceName = NewPipe.getNameOfService(info.getServiceId());
final ImageLoadingListener onFailListener = new SimpleImageLoadingListener() { final ImageLoadingListener onFailListener = new SimpleImageLoadingListener() {
@Override @Override
@ -763,12 +770,12 @@ public final class VideoDetailFragment
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, onFailListener); ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, onFailListener);
} }
if (!TextUtils.isEmpty(info.getSubChannelAvatarUrl())) { if (!isEmpty(info.getSubChannelAvatarUrl())) {
IMAGE_LOADER.displayImage(info.getSubChannelAvatarUrl(), subChannelThumb, IMAGE_LOADER.displayImage(info.getSubChannelAvatarUrl(), subChannelThumb,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
} }
if (!TextUtils.isEmpty(info.getUploaderAvatarUrl())) { if (!isEmpty(info.getUploaderAvatarUrl())) {
IMAGE_LOADER.displayImage(info.getUploaderAvatarUrl(), uploaderThumb, IMAGE_LOADER.displayImage(info.getUploaderAvatarUrl(), uploaderThumb,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
} }
@ -1217,7 +1224,7 @@ public final class VideoDetailFragment
} }
private void prepareDescription(final Description description) { private void prepareDescription(final Description description) {
if (description == null || TextUtils.isEmpty(description.getContent()) if (description == null || isEmpty(description.getContent())
|| description == Description.emptyDescription) { || description == Description.emptyDescription) {
return; return;
} }
@ -1462,9 +1469,9 @@ public final class VideoDetailFragment
animateView(thumbnailPlayButton, true, 200); animateView(thumbnailPlayButton, true, 200);
videoTitleTextView.setText(title); videoTitleTextView.setText(title);
if (!TextUtils.isEmpty(info.getSubChannelName())) { if (!isEmpty(info.getSubChannelName())) {
displayBothUploaderAndSubChannel(info); displayBothUploaderAndSubChannel(info);
} else if (!TextUtils.isEmpty(info.getUploaderName())) { } else if (!isEmpty(info.getUploaderName())) {
displayUploaderAsSubChannel(info); displayUploaderAsSubChannel(info);
} else { } else {
uploaderTextView.setVisibility(View.GONE); uploaderTextView.setVisibility(View.GONE);
@ -1559,6 +1566,8 @@ public final class VideoDetailFragment
prepareDescription(info.getDescription()); prepareDescription(info.getDescription());
updateProgressInfo(info); updateProgressInfo(info);
initThumbnailViews(info); initThumbnailViews(info);
showMetaInfoInTextView(info.getMetaInfo(), detailMetaInfoTextView, detailMetaInfoSeparator);
if (player == null || player.isPlayerStopped()) { if (player == null || player.isPlayerStopped()) {
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl()); updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
@ -1610,7 +1619,7 @@ public final class VideoDetailFragment
subChannelThumb.setVisibility(View.VISIBLE); subChannelThumb.setVisibility(View.VISIBLE);
if (!TextUtils.isEmpty(info.getUploaderName())) { if (!isEmpty(info.getUploaderName())) {
uploaderTextView.setText( uploaderTextView.setText(
String.format(getString(R.string.video_detail_by), info.getUploaderName())); String.format(getString(R.string.video_detail_by), info.getUploaderName()));
uploaderTextView.setVisibility(View.VISIBLE); uploaderTextView.setVisibility(View.VISIBLE);
@ -2305,10 +2314,10 @@ public final class VideoDetailFragment
private void updateOverlayData(@Nullable final String overlayTitle, private void updateOverlayData(@Nullable final String overlayTitle,
@Nullable final String uploader, @Nullable final String uploader,
@Nullable final String thumbnailUrl) { @Nullable final String thumbnailUrl) {
overlayTitleTextView.setText(TextUtils.isEmpty(overlayTitle) ? "" : overlayTitle); overlayTitleTextView.setText(isEmpty(title) ? "" : title);
overlayChannelTextView.setText(TextUtils.isEmpty(uploader) ? "" : uploader); overlayChannelTextView.setText(isEmpty(uploader) ? "" : uploader);
overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark); overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
if (!TextUtils.isEmpty(thumbnailUrl)) { if (!isEmpty(thumbnailUrl)) {
IMAGE_LOADER.displayImage(thumbnailUrl, overlayThumbnailImageView, IMAGE_LOADER.displayImage(thumbnailUrl, overlayThumbnailImageView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, null); ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, null);
} }

View file

@ -39,6 +39,7 @@ import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.database.history.model.SearchHistoryEntry; import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.MetaInfo;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.Page; import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
@ -79,6 +80,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject;
import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags; import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static org.schabi.newpipe.util.AnimationUtils.animateView; import static org.schabi.newpipe.util.AnimationUtils.animateView;
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage<?>> public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage<?>>
implements BackPressable { implements BackPressable {
@ -129,6 +131,9 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
@State @State
boolean isCorrectedSearch; boolean isCorrectedSearch;
@State
MetaInfo[] metaInfo;
@State @State
boolean wasSearchFocused = false; boolean wasSearchFocused = false;
@ -153,6 +158,8 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
private View searchClear; private View searchClear;
private TextView correctSuggestion; private TextView correctSuggestion;
private TextView metaInfoTextView;
private View metaInfoSeparator;
private View suggestionsPanel; private View suggestionsPanel;
private boolean suggestionsPanelVisible = false; private boolean suggestionsPanelVisible = false;
@ -269,6 +276,9 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
handleSearchSuggestion(); handleSearchSuggestion();
showMetaInfoInTextView(metaInfo == null ? null : Arrays.asList(metaInfo),
metaInfoTextView, metaInfoSeparator);
if (suggestionDisposable == null || suggestionDisposable.isDisposed()) { if (suggestionDisposable == null || suggestionDisposable.isDisposed()) {
initSuggestionObserver(); initSuggestionObserver();
} }
@ -353,6 +363,8 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
searchClear = searchToolbarContainer.findViewById(R.id.toolbar_search_clear); searchClear = searchToolbarContainer.findViewById(R.id.toolbar_search_clear);
correctSuggestion = rootView.findViewById(R.id.correct_suggestion); correctSuggestion = rootView.findViewById(R.id.correct_suggestion);
metaInfoTextView = rootView.findViewById(R.id.search_meta_info_text_view);
metaInfoSeparator = rootView.findViewById(R.id.search_meta_info_separator);
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -973,8 +985,14 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
searchSuggestion = result.getSearchSuggestion(); searchSuggestion = result.getSearchSuggestion();
isCorrectedSearch = result.isCorrectedSearch(); isCorrectedSearch = result.isCorrectedSearch();
// List<MetaInfo> cannot be bundled without creating some containers
metaInfo = new MetaInfo[result.getMetaInfo().size()];
metaInfo = result.getMetaInfo().toArray(metaInfo);
handleSearchSuggestion(); handleSearchSuggestion();
showMetaInfoInTextView(result.getMetaInfo(), metaInfoTextView, metaInfoSeparator);
lastSearchedString = searchString; lastSearchedString = searchString;
nextPage = result.getNextPage(); nextPage = result.getNextPage();

View file

@ -22,9 +22,16 @@ package org.schabi.newpipe.util;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Handler; import android.os.Handler;
import android.text.method.LinkMovementMethod;
import android.util.Log; import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.core.text.HtmlCompat;
import androidx.preference.PreferenceManager;
import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.ReCaptchaActivity; import org.schabi.newpipe.ReCaptchaActivity;
@ -32,6 +39,7 @@ import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage; import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
import org.schabi.newpipe.extractor.ListInfo; import org.schabi.newpipe.extractor.ListInfo;
import org.schabi.newpipe.extractor.MetaInfo;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.Page; import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
@ -60,6 +68,8 @@ import java.util.List;
import io.reactivex.rxjava3.core.Maybe; import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.core.Single;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
public final class ExtractorHelper { public final class ExtractorHelper {
private static final String TAG = ExtractorHelper.class.getSimpleName(); private static final String TAG = ExtractorHelper.class.getSimpleName();
private static final InfoCache CACHE = InfoCache.getInstance(); private static final InfoCache CACHE = InfoCache.getInstance();
@ -306,4 +316,73 @@ public final class ExtractorHelper {
} }
}); });
} }
/**
* Formats the text contained in the meta info list as HTML and puts it into the text view,
* while also making the separator visible. If the list is null or empty, or the user chose not
* to see meta information, both the text view and the separator are hidden
* @param metaInfos a list of meta information, can be null or empty
* @param metaInfoTextView the text view in which to show the formatted HTML
* @param metaInfoSeparator another view to be shown or hidden accordingly to the text view
*/
public static void showMetaInfoInTextView(@Nullable final List<MetaInfo> metaInfos,
final TextView metaInfoTextView,
final View metaInfoSeparator) {
final Context context = metaInfoTextView.getContext();
final boolean showMetaInfo = PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(context.getString(R.string.show_meta_info_key), true);
if (!showMetaInfo || metaInfos == null || metaInfos.isEmpty()) {
metaInfoTextView.setVisibility(View.GONE);
metaInfoSeparator.setVisibility(View.GONE);
} else {
final StringBuilder stringBuilder = new StringBuilder();
for (final MetaInfo metaInfo : metaInfos) {
if (!isNullOrEmpty(metaInfo.getTitle())) {
stringBuilder.append("<b>").append(metaInfo.getTitle()).append("</b>")
.append(Localization.DOT_SEPARATOR);
}
String content = metaInfo.getContent().getContent().trim();
if (content.endsWith(".")) {
content = content.substring(0, content.length() - 1); // remove . at end
}
stringBuilder.append(content);
for (int i = 0; i < metaInfo.getUrls().size(); i++) {
if (i == 0) {
stringBuilder.append(Localization.DOT_SEPARATOR);
} else {
stringBuilder.append("<br/><br/>");
}
stringBuilder
.append("<a href=\"").append(metaInfo.getUrls().get(i)).append("\">")
.append(capitalizeIfAllUppercase(metaInfo.getUrlTexts().get(i).trim()))
.append("</a>");
}
}
metaInfoTextView.setText(HtmlCompat.fromHtml(stringBuilder.toString(),
HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING));
metaInfoTextView.setMovementMethod(LinkMovementMethod.getInstance());
metaInfoTextView.setVisibility(View.VISIBLE);
metaInfoSeparator.setVisibility(View.VISIBLE);
}
}
private static String capitalizeIfAllUppercase(final String text) {
for (int i = 0; i < text.length(); i++) {
if (Character.isLowerCase(text.charAt(i))) {
return text; // there is at least a lowercase letter -> not all uppercase
}
}
if (text.isEmpty()) {
return text;
} else {
return text.substring(0, 1).toUpperCase() + text.substring(1).toLowerCase();
}
}
} }

View file

@ -57,7 +57,7 @@ import java.util.Locale;
public final class Localization { public final class Localization {
private static final String DOT_SEPARATOR = ""; public static final String DOT_SEPARATOR = "";
private static PrettyTime prettyTime; private static PrettyTime prettyTime;
private Localization() { } private Localization() { }

View file

@ -506,6 +506,23 @@
</LinearLayout> </LinearLayout>
<View
android:id="@+id/detail_meta_info_separator"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="?attr/separator_color" />
<TextView
android:id="@+id/detail_meta_info_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="12dp"
android:textSize="@dimen/video_item_detail_description_text_size"
tools:text="Stream meta info with link" />
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="1px" android:layout_height="1px"

View file

@ -11,15 +11,34 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignTop="@id/error_panel" android:layout_alignTop="@id/error_panel"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
android:padding="10dp" android:padding="12dp"
android:textSize="@dimen/search_suggestion_text_size" android:textSize="@dimen/search_suggestion_text_size"
tools:text="Showing results for lorem ipsum dolor sit amet consectetur adipisci elit" /> tools:text="Showing results for lorem ipsum dolor sit amet consectetur adipisci elit" />
<TextView
android:id="@+id/search_meta_info_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/correct_suggestion"
android:gravity="center"
android:padding="12dp"
android:textSize="@dimen/video_item_detail_description_text_size"
tools:text="Get the latest information from the WHO about coronavirus." />
<View
android:id="@+id/search_meta_info_separator"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_below="@id/search_meta_info_text_view"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="?attr/separator_color" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/items_list" android:id="@+id/items_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_below="@+id/correct_suggestion" android:layout_below="@+id/search_meta_info_separator"
android:scrollbars="vertical" android:scrollbars="vertical"
app:layoutManager="LinearLayoutManager" app:layoutManager="LinearLayoutManager"
tools:listitem="@layout/list_stream_item" /> tools:listitem="@layout/list_stream_item" />

View file

@ -491,6 +491,23 @@
</LinearLayout> </LinearLayout>
<View
android:id="@+id/detail_meta_info_separator"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="?attr/separator_color" />
<TextView
android:id="@+id/detail_meta_info_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="12dp"
android:textSize="@dimen/video_item_detail_description_text_size"
tools:text="Stream meta info with link" />
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="1px" android:layout_height="1px"

View file

@ -197,6 +197,7 @@
<string name="show_play_with_kodi_key" translatable="false">show_play_with_kodi</string> <string name="show_play_with_kodi_key" translatable="false">show_play_with_kodi</string>
<string name="show_next_video_key" translatable="false">show_next_video</string> <string name="show_next_video_key" translatable="false">show_next_video</string>
<string name="show_comments_key" translatable="false">show_comments</string> <string name="show_comments_key" translatable="false">show_comments</string>
<string name="show_meta_info_key" translatable="false">show_meta_info</string>
<string name="stream_info_selected_tab_key" translatable="false">stream_info_selected_tab</string> <string name="stream_info_selected_tab_key" translatable="false">stream_info_selected_tab</string>
<string name="show_hold_to_append_key" translatable="false">show_hold_to_append</string> <string name="show_hold_to_append_key" translatable="false">show_hold_to_append</string>
<string name="content_language_key" translatable="false">content_language</string> <string name="content_language_key" translatable="false">content_language</string>

View file

@ -93,6 +93,8 @@
<string name="show_comments_title">Show comments</string> <string name="show_comments_title">Show comments</string>
<string name="show_comments_summary">Turn off to hide comments</string> <string name="show_comments_summary">Turn off to hide comments</string>
<string name="download_thumbnail_summary">Turn off to prevent loading thumbnails, saving data and memory usage. Changes clear both in-memory and on-disk image cache.</string> <string name="download_thumbnail_summary">Turn off to prevent loading thumbnails, saving data and memory usage. Changes clear both in-memory and on-disk image cache.</string>
<string name="show_meta_info_title">Show meta info</string>
<string name="show_meta_info_summary">Turn off to hide meta info boxes with additional information about the stream creator, stream content or a search request.</string>
<string name="thumbnail_cache_wipe_complete_notice">Image cache wiped</string> <string name="thumbnail_cache_wipe_complete_notice">Image cache wiped</string>
<string name="metadata_cache_wipe_title">Wipe cached metadata</string> <string name="metadata_cache_wipe_title">Wipe cached metadata</string>
<string name="metadata_cache_wipe_summary">Remove all cached webpage data</string> <string name="metadata_cache_wipe_summary">Remove all cached webpage data</string>

View file

@ -85,6 +85,13 @@
android:title="@string/show_comments_title" android:title="@string/show_comments_title"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="@string/show_meta_info_key"
android:summary="@string/show_meta_info_summary"
android:title="@string/show_meta_info_title"
app:iconSpaceReserved="false" />
<Preference <Preference
android:key="@string/import_data" android:key="@string/import_data"
android:summary="@string/import_data_summary" android:summary="@string/import_data_summary"