1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2024-12-23 08:30:44 +00:00

Improve text linkifier function parameters

This commit is contained in:
Stypox 2021-06-05 14:59:23 +02:00 committed by TiA4f8R
parent 218f25c171
commit eef418a757
No known key found for this signature in database
GPG Key ID: E6D3E7F5949450DD
4 changed files with 74 additions and 94 deletions

View File

@ -16,9 +16,9 @@ import org.schabi.newpipe.BuildConfig
import org.schabi.newpipe.R
import org.schabi.newpipe.databinding.ActivityAboutBinding
import org.schabi.newpipe.databinding.FragmentAboutBinding
import org.schabi.newpipe.util.external_communication.ShareUtils
import org.schabi.newpipe.util.Localization
import org.schabi.newpipe.util.ThemeHelper
import org.schabi.newpipe.util.external_communication.ShareUtils
class AboutActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -19,7 +19,6 @@ import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.FragmentDescriptionBinding;
import org.schabi.newpipe.databinding.ItemMetadataBinding;
import org.schabi.newpipe.databinding.ItemMetadataTagsBinding;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.stream.Description;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.util.Localization;
@ -132,24 +131,19 @@ public class DescriptionFragment extends BaseFragment {
private void loadDescriptionContent() {
final Description description = streamInfo.getDescription();
final String contentUrl = streamInfo.getUrl();
final StreamingService service = streamInfo.getService();
switch (description.getType()) {
case Description.HTML:
descriptionDisposable = TextLinkifier.createLinksFromHtmlBlock(requireContext(),
description.getContent(), binding.detailDescriptionView,
service, contentUrl, HtmlCompat.FROM_HTML_MODE_LEGACY);
descriptionDisposable = TextLinkifier.createLinksFromHtmlBlock(
binding.detailDescriptionView, description.getContent(),
HtmlCompat.FROM_HTML_MODE_LEGACY, streamInfo);
break;
case Description.MARKDOWN:
descriptionDisposable = TextLinkifier.createLinksFromMarkdownText(requireContext(),
description.getContent(), binding.detailDescriptionView,
service, contentUrl);
descriptionDisposable = TextLinkifier.createLinksFromMarkdownText(
binding.detailDescriptionView, description.getContent(), streamInfo);
break;
case Description.PLAIN_TEXT: default:
descriptionDisposable = TextLinkifier.createLinksFromPlainText(requireContext(),
description.getContent(), binding.detailDescriptionView,
service, contentUrl);
descriptionDisposable = TextLinkifier.createLinksFromPlainText(
binding.detailDescriptionView, description.getContent(), streamInfo);
break;
}
}
@ -204,8 +198,7 @@ public class DescriptionFragment extends BaseFragment {
});
if (linkifyContent) {
TextLinkifier.createLinksFromPlainText(requireContext(),
content, itemBinding.metadataContentView, null, null);
TextLinkifier.createLinksFromPlainText(itemBinding.metadataContentView, content, null);
} else {
itemBinding.metadataContentView.setText(content);
}

View File

@ -311,9 +311,9 @@ public final class ExtractorHelper {
}
metaInfoSeparator.setVisibility(View.VISIBLE);
return TextLinkifier.createLinksFromHtmlBlock(context, stringBuilder.toString(),
metaInfoTextView, null, null,
HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING);
return TextLinkifier.createLinksFromHtmlBlock(metaInfoTextView,
stringBuilder.toString(), HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING,
null);
}
}

View File

@ -11,9 +11,10 @@ import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.text.HtmlCompat;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.util.NavigationHelper;
import java.util.regex.Matcher;
@ -42,85 +43,74 @@ public final class TextLinkifier {
* Create web links for contents with an HTML description.
* <p>
* This will call
* {@link TextLinkifier#changeIntentsOfDescriptionLinks(Context, CharSequence, TextView,
* StreamingService, String)}
* {@link TextLinkifier#changeIntentsOfDescriptionLinks(TextView, CharSequence, Info)}
* after having linked the URLs with {@link HtmlCompat#fromHtml(String, int)}.
*
* @param context the context to use
* @param htmlBlock the htmlBlock to be linked
* @param textView the TextView to set the htmlBlock linked
* @param streamingService the {@link StreamingService} of the content
* @param contentUrl the URL of the content
* @param htmlCompatFlag the int flag to be set when {@link HtmlCompat#fromHtml(String, int)}
* will be called
* @param textView the TextView to set the htmlBlock linked
* @param htmlBlock the htmlBlock to be linked
* @param htmlCompatFlag the int flag to be set when {@link HtmlCompat#fromHtml(String, int)}
* will be called
* @param relatedInfo if given, handle timestamps to open the stream in the popup player at
* the specific time, and hashtags to search for the term in the correct
* service
* @return a disposable to be stored somewhere and disposed when activity/fragment is destroyed
*/
@NonNull
public static Disposable createLinksFromHtmlBlock(final Context context,
public static Disposable createLinksFromHtmlBlock(@NonNull final TextView textView,
final String htmlBlock,
final TextView textView,
final StreamingService streamingService,
final String contentUrl,
final int htmlCompatFlag) {
return changeIntentsOfDescriptionLinks(context,
HtmlCompat.fromHtml(htmlBlock, htmlCompatFlag), textView, streamingService,
contentUrl);
final int htmlCompatFlag,
@Nullable final Info relatedInfo) {
return changeIntentsOfDescriptionLinks(
textView, HtmlCompat.fromHtml(htmlBlock, htmlCompatFlag), relatedInfo);
}
/**
* Create web links for contents with a plain text description.
* <p>
* This will call
* {@link TextLinkifier#changeIntentsOfDescriptionLinks(Context, CharSequence, TextView,
* StreamingService, String)}
* {@link TextLinkifier#changeIntentsOfDescriptionLinks(TextView, CharSequence, Info)}
* after having linked the URLs with {@link TextView#setAutoLinkMask(int)} and
* {@link TextView#setText(CharSequence, TextView.BufferType)}.
*
* @param context the context to use
* @param plainTextBlock the block of plain text to be linked
* @param textView the TextView to set the plain text block linked
* @param streamingService the {@link StreamingService} of the content
* @param contentUrl the URL of the content
* @param textView the TextView to set the plain text block linked
* @param plainTextBlock the block of plain text to be linked
* @param relatedInfo if given, handle timestamps to open the stream in the popup player at
* the specific time, and hashtags to search for the term in the correct
* service
* @return a disposable to be stored somewhere and disposed when activity/fragment is destroyed
*/
@NonNull
public static Disposable createLinksFromPlainText(final Context context,
public static Disposable createLinksFromPlainText(@NonNull final TextView textView,
final String plainTextBlock,
@NonNull final TextView textView,
final StreamingService streamingService,
final String contentUrl) {
@Nullable final Info relatedInfo) {
textView.setAutoLinkMask(Linkify.WEB_URLS);
textView.setText(plainTextBlock, TextView.BufferType.SPANNABLE);
return changeIntentsOfDescriptionLinks(context, textView.getText(), textView,
streamingService, contentUrl);
return changeIntentsOfDescriptionLinks(textView, textView.getText(), relatedInfo);
}
/**
* Create web links for contents with a markdown description.
* <p>
* This will call
* {@link TextLinkifier#changeIntentsOfDescriptionLinks(Context, CharSequence, TextView,
* StreamingService, String)}
* {@link TextLinkifier#changeIntentsOfDescriptionLinks(TextView, CharSequence, Info)}
* after creating an {@link Markwon} object and using
* {@link Markwon#setMarkdown(TextView, String)}.
*
* @param context the context to use
* @param markdownBlock the block of markdown text to be linked
* @param textView the TextView to set the plain text block linked
* @param streamingService the {@link StreamingService} of the content
* @param contentUrl the URL of the content
* @param textView the TextView to set the plain text block linked
* @param markdownBlock the block of markdown text to be linked
* @param relatedInfo if given, handle timestamps to open the stream in the popup player at
* the specific time, and hashtags to search for the term in the correct
* service
* @return a disposable to be stored somewhere and disposed when activity/fragment is destroyed
*/
@NonNull
public static Disposable createLinksFromMarkdownText(final Context context,
public static Disposable createLinksFromMarkdownText(@NonNull final TextView textView,
final String markdownBlock,
final TextView textView,
final StreamingService streamingService,
final String contentUrl) {
final Markwon markwon = Markwon.builder(context).usePlugin(LinkifyPlugin.create()).build();
@Nullable final Info relatedInfo) {
final Markwon markwon = Markwon.builder(textView.getContext())
.usePlugin(LinkifyPlugin.create()).build();
markwon.setMarkdown(textView, markdownBlock);
return changeIntentsOfDescriptionLinks(context, textView.getText(), textView,
streamingService, contentUrl);
return changeIntentsOfDescriptionLinks(textView, textView.getText(), relatedInfo);
}
/**
@ -134,12 +124,12 @@ public final class TextLinkifier {
* @param context the context to use
* @param spannableDescription the SpannableStringBuilder with the text of the
* content description
* @param streamingService the {@link StreamingService} of the content
* @param relatedInfo used to search for the term in the correct service
*/
private static void addClickListenersOnHashtags(final Context context,
@NonNull final SpannableStringBuilder
spannableDescription,
final StreamingService streamingService) {
final Info relatedInfo) {
final String descriptionText = spannableDescription.toString();
final Matcher hashtagsMatches = HASHTAGS_PATTERN.matcher(descriptionText);
@ -155,7 +145,7 @@ public final class TextLinkifier {
spannableDescription.setSpan(new ClickableSpan() {
@Override
public void onClick(@NonNull final View view) {
NavigationHelper.openSearch(context, streamingService.getServiceId(),
NavigationHelper.openSearch(context, relatedInfo.getServiceId(),
parsedHashtag);
}
}, hashtagStart, hashtagEnd, 0);
@ -173,14 +163,12 @@ public final class TextLinkifier {
* @param context the context to use
* @param spannableDescription the SpannableStringBuilder with the text of the
* content description
* @param contentUrl the URL of the content
* @param streamingService the {@link StreamingService} of the content
* @param relatedInfo what to open in the popup player when timestamps are clicked
*/
private static void addClickListenersOnTimestamps(final Context context,
@NonNull final SpannableStringBuilder
spannableDescription,
final String contentUrl,
final StreamingService streamingService) {
final Info relatedInfo) {
final String descriptionText = spannableDescription.toString();
final Matcher timestampsMatches = TIMESTAMPS_PATTERN.matcher(descriptionText);
@ -189,14 +177,14 @@ public final class TextLinkifier {
final int timestampEnd = timestampsMatches.end(3);
final String parsedTimestamp = descriptionText.substring(timestampStart, timestampEnd);
final String[] timestampParts = parsedTimestamp.split(":");
final int time;
final int seconds;
if (timestampParts.length == 3) { // timestamp format: XX:XX:XX
time = Integer.parseInt(timestampParts[0]) * 3600 // hours
seconds = Integer.parseInt(timestampParts[0]) * 3600 // hours
+ Integer.parseInt(timestampParts[1]) * 60 // minutes
+ Integer.parseInt(timestampParts[2]); // seconds
} else if (timestampParts.length == 2) { // timestamp format: XX:XX
time = Integer.parseInt(timestampParts[0]) * 60 // minutes
seconds = Integer.parseInt(timestampParts[0]) * 60 // minutes
+ Integer.parseInt(timestampParts[1]); // seconds
} else {
continue;
@ -205,8 +193,8 @@ public final class TextLinkifier {
spannableDescription.setSpan(new ClickableSpan() {
@Override
public void onClick(@NonNull final View view) {
playOnPopup(new CompositeDisposable(), context, contentUrl, streamingService,
time);
playOnPopup(new CompositeDisposable(), context, relatedInfo.getUrl(),
relatedInfo.getService(), seconds);
}
}, timestampStart, timestampEnd, 0);
}
@ -221,28 +209,28 @@ public final class TextLinkifier {
* with {@link ShareUtils#openUrlInBrowser(Context, String, boolean)}.
* This method will also add click listeners on timestamps in this description, which will play
* the content in the popup player at the time indicated in the timestamp, by using
* {@link TextLinkifier#addClickListenersOnTimestamps(Context, SpannableStringBuilder, String,
* StreamingService)} method and click listeners on hashtags, which will open a search
* on the current service with the hashtag.
* {@link TextLinkifier#addClickListenersOnTimestamps(Context, SpannableStringBuilder, Info)}
* method and click listeners on hashtags, by using
* {@link TextLinkifier#addClickListenersOnHashtags(Context, SpannableStringBuilder, Info)},
* which will open a search on the current service with the hashtag.
* <p>
* This method is required in order to intercept links and e.g. show a confirmation dialog
* before opening a web link.
*
* @param context the context to use
* @param chars the CharSequence to be parsed
* @param textView the TextView in which the converted CharSequence will be applied
* @param streamingService the {@link StreamingService} of the content
* @param contentUrl the URL of the content
* @param textView the TextView in which the converted CharSequence will be applied
* @param chars the CharSequence to be parsed
* @param relatedInfo if given, handle timestamps to open the stream in the popup player at
* the specific time, and hashtags to search for the term in the correct
* service
* @return a disposable to be stored somewhere and disposed when activity/fragment is destroyed
*/
@NonNull
private static Disposable changeIntentsOfDescriptionLinks(final Context context,
private static Disposable changeIntentsOfDescriptionLinks(final TextView textView,
final CharSequence chars,
final TextView textView,
final StreamingService
streamingService,
final String contentUrl) {
@Nullable final Info relatedInfo) {
return Single.fromCallable(() -> {
final Context context = textView.getContext();
// add custom click actions on web links
final SpannableStringBuilder textBlockLinked = new SpannableStringBuilder(chars);
final URLSpan[] urls = textBlockLinked.getSpans(0, chars.length(), URLSpan.class);
@ -264,11 +252,10 @@ public final class TextLinkifier {
}
// add click actions on plain text timestamps only for description of contents,
// unneeded for metainfo TextViews
if (contentUrl != null || streamingService != null) {
addClickListenersOnTimestamps(context, textBlockLinked, contentUrl,
streamingService);
addClickListenersOnHashtags(context, textBlockLinked, streamingService);
// unneeded for meta-info or other TextViews
if (relatedInfo != null) {
addClickListenersOnTimestamps(context, textBlockLinked, relatedInfo);
addClickListenersOnHashtags(context, textBlockLinked, relatedInfo);
}
return textBlockLinked;