Display meta info about search query, stream creator or topic
Closes #4614
This commit is contained in:
parent
0c656abb8e
commit
0a831ec84e
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -16,7 +16,7 @@ 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.method.LinkMovementMethod;
|
||||||
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;
|
||||||
|
@ -63,6 +63,7 @@ import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.ReCaptchaActivity;
|
import org.schabi.newpipe.ReCaptchaActivity;
|
||||||
import org.schabi.newpipe.download.DownloadDialog;
|
import org.schabi.newpipe.download.DownloadDialog;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
|
import org.schabi.newpipe.extractor.MetaInfo;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.ServiceList;
|
import org.schabi.newpipe.extractor.ServiceList;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
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.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.extractor.utils.Utils.isNullOrEmpty;
|
||||||
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;
|
||||||
|
@ -218,6 +221,10 @@ public final class VideoDetailFragment
|
||||||
private TextView detailDurationView;
|
private TextView detailDurationView;
|
||||||
private TextView detailPositionView;
|
private TextView detailPositionView;
|
||||||
|
|
||||||
|
private LinearLayout detailMetadataInfo;
|
||||||
|
private View detailMetadataInfoSeparator;
|
||||||
|
private TextView detailMetadataInfoText;
|
||||||
|
|
||||||
private LinearLayout videoDescriptionRootLayout;
|
private LinearLayout videoDescriptionRootLayout;
|
||||||
private TextView videoUploadDateView;
|
private TextView videoUploadDateView;
|
||||||
private TextView videoDescriptionView;
|
private TextView videoDescriptionView;
|
||||||
|
@ -508,8 +515,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 +590,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 +651,10 @@ 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);
|
||||||
|
|
||||||
|
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);
|
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 +759,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 +774,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 +1228,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;
|
||||||
}
|
}
|
||||||
|
@ -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<MetaInfo> metaIfs = info.getMetaInfo();
|
||||||
|
final StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
for (final MetaInfo mi: metaIfs) {
|
||||||
|
if (!isNullOrEmpty(mi.getTitle())) {
|
||||||
|
stringBuilder.append("<h2>").append(mi.getTitle()).append("</h2>");
|
||||||
|
}
|
||||||
|
stringBuilder.append(mi.getContent().getContent());
|
||||||
|
for (int i = 0; i < mi.getUrls().size(); i++) {
|
||||||
|
stringBuilder
|
||||||
|
.append(" <a href=\"").append(mi.getUrls().get(i)).append("\">")
|
||||||
|
.append(mi.getUrlTexts().get(i))
|
||||||
|
.append("</a>");
|
||||||
|
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("<br>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 =
|
private final ViewTreeObserver.OnPreDrawListener preDrawListener =
|
||||||
new ViewTreeObserver.OnPreDrawListener() {
|
new ViewTreeObserver.OnPreDrawListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -1462,9 +1509,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 +1606,8 @@ public final class VideoDetailFragment
|
||||||
prepareDescription(info.getDescription());
|
prepareDescription(info.getDescription());
|
||||||
updateProgressInfo(info);
|
updateProgressInfo(info);
|
||||||
initThumbnailViews(info);
|
initThumbnailViews(info);
|
||||||
|
setMetaInfo(info);
|
||||||
|
|
||||||
|
|
||||||
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 +1659,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 +2354,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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import android.text.Editable;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
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.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;
|
||||||
|
@ -78,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.extractor.utils.Utils.isNullOrEmpty;
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage<?>>
|
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage<?>>
|
||||||
|
@ -129,6 +132,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 +159,7 @@ 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 suggestionsPanel;
|
private View suggestionsPanel;
|
||||||
private boolean suggestionsPanelVisible = false;
|
private boolean suggestionsPanelVisible = false;
|
||||||
|
@ -269,6 +276,8 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
|
|
||||||
handleSearchSuggestion();
|
handleSearchSuggestion();
|
||||||
|
|
||||||
|
handleMetaInfo();
|
||||||
|
|
||||||
if (suggestionDisposable == null || suggestionDisposable.isDisposed()) {
|
if (suggestionDisposable == null || suggestionDisposable.isDisposed()) {
|
||||||
initSuggestionObserver();
|
initSuggestionObserver();
|
||||||
}
|
}
|
||||||
|
@ -353,6 +362,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -973,7 +983,12 @@ 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();
|
||||||
|
handleMetaInfo();
|
||||||
|
|
||||||
lastSearchedString = searchString;
|
lastSearchedString = searchString;
|
||||||
nextPage = result.getNextPage();
|
nextPage = result.getNextPage();
|
||||||
|
@ -1021,6 +1036,39 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleMetaInfo() {
|
||||||
|
final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
|
||||||
|
requireContext());
|
||||||
|
final boolean showMetaInfo = sp.getBoolean(
|
||||||
|
requireContext().getString(R.string.show_meta_info_key), true);
|
||||||
|
if (metaInfo == null || metaInfo.length == 0 || !showMetaInfo) {
|
||||||
|
metaInfoTextView.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
final StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
for (final MetaInfo mi: metaInfo) {
|
||||||
|
if (!isNullOrEmpty(mi.getTitle())) {
|
||||||
|
stringBuilder.append("<h2>").append(mi.getTitle()).append("</h2>");
|
||||||
|
}
|
||||||
|
stringBuilder.append(mi.getContent().getContent());
|
||||||
|
for (int i = 0; i < mi.getUrls().size(); i++) {
|
||||||
|
stringBuilder
|
||||||
|
.append(" <a href=\"").append(mi.getUrls().get(i)).append("\">")
|
||||||
|
.append(mi.getUrlTexts().get(i))
|
||||||
|
.append("</a>");
|
||||||
|
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("<br>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
metaInfoTextView.setText(HtmlCompat.fromHtml(
|
||||||
|
stringBuilder.toString(), HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING));
|
||||||
|
metaInfoTextView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
metaInfoTextView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleNextItems(final ListExtractor.InfoItemsPage<?> result) {
|
public void handleNextItems(final ListExtractor.InfoItemsPage<?> result) {
|
||||||
showListFooter(false);
|
showListFooter(false);
|
||||||
|
|
|
@ -506,6 +506,38 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/detail_metadata_info_separator"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1px"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:background="?attr/separator_color" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/detail_metadata_info"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
app:srcCompat="?attr/ic_info_outline" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_metadata_info_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
tools:text="Stream meta info with link"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1px"
|
android:layout_height="1px"
|
||||||
|
|
|
@ -11,15 +11,25 @@
|
||||||
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"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/correct_suggestion"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textSize="@dimen/search_suggestion_text_size"
|
||||||
|
tools:text="Get the latest information from the WHO about coronavirus." />
|
||||||
|
|
||||||
|
|
||||||
<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"
|
||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"
|
||||||
app:layoutManager="LinearLayoutManager"
|
app:layoutManager="LinearLayoutManager"
|
||||||
tools:listitem="@layout/list_stream_item" />
|
tools:listitem="@layout/list_stream_item" />
|
||||||
|
|
|
@ -491,6 +491,39 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/detail_metadata_info_separator"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1px"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:background="?attr/separator_color" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/detail_metadata_info"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
app:srcCompat="?attr/ic_info_outline" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_metadata_info_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
tools:text="Stream meta info with link"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1px"
|
android:layout_height="1px"
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue