diff --git a/app/src/main/java/org/schabi/newpipe/util/text/TextEllipsizer.java b/app/src/main/java/org/schabi/newpipe/util/text/TextEllipsizer.java deleted file mode 100644 index 184b73304d8..00000000000 --- a/app/src/main/java/org/schabi/newpipe/util/text/TextEllipsizer.java +++ /dev/null @@ -1,193 +0,0 @@ -package org.schabi.newpipe.util.text; - -import android.graphics.Paint; -import android.text.Layout; -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.stream.Description; - -import java.util.function.Consumer; - - -import io.reactivex.rxjava3.disposables.CompositeDisposable; - -/** - *

Class to ellipsize text inside a {@link TextView}.

- * This class provides all utils to automatically ellipsize and expand a text - */ -public final class TextEllipsizer { - private static final int EXPANDED_LINES = Integer.MAX_VALUE; - private static final String ELLIPSIS = "…"; - - @NonNull private final CompositeDisposable disposable = new CompositeDisposable(); - - @NonNull private final TextView view; - private final int maxLines; - @NonNull private Description content; - @Nullable private StreamingService streamingService; - @Nullable private String streamUrl; - private boolean isEllipsized = false; - @Nullable private Boolean canBeEllipsized = null; - - @NonNull private final Paint paintAtContentSize = new Paint(); - private final float ellipsisWidthPx; - @Nullable private Consumer stateChangeListener = null; - @Nullable private Consumer onContentChanged; - - public TextEllipsizer(@NonNull final TextView view, - final int maxLines, - @Nullable final StreamingService streamingService) { - this.view = view; - this.maxLines = maxLines; - this.content = Description.EMPTY_DESCRIPTION; - this.streamingService = streamingService; - - paintAtContentSize.setTextSize(view.getTextSize()); - ellipsisWidthPx = paintAtContentSize.measureText(ELLIPSIS); - } - - public void setOnContentChanged(@Nullable final Consumer onContentChanged) { - this.onContentChanged = onContentChanged; - } - - public void setContent(@NonNull final Description content) { - this.content = content; - canBeEllipsized = null; - linkifyContentView(v -> { - final int currentMaxLines = view.getMaxLines(); - view.setMaxLines(EXPANDED_LINES); - canBeEllipsized = view.getLineCount() > maxLines; - view.setMaxLines(currentMaxLines); - if (onContentChanged != null) { - onContentChanged.accept(canBeEllipsized); - } - }); - } - - public void setStreamUrl(@Nullable final String streamUrl) { - this.streamUrl = streamUrl; - } - - public void setStreamingService(@NonNull final StreamingService streamingService) { - this.streamingService = streamingService; - } - - /** - * Expand the {@link TextEllipsizer#content} to its full length. - */ - public void expand() { - view.setMaxLines(EXPANDED_LINES); - linkifyContentView(v -> isEllipsized = false); - } - - /** - * Shorten the {@link TextEllipsizer#content} to the given number of - * {@link TextEllipsizer#maxLines maximum lines} and add trailing '{@code …}' - * if the text was shorted. - */ - public void ellipsize() { - // expand text to see whether it is necessary to ellipsize the text - view.setMaxLines(EXPANDED_LINES); - linkifyContentView(v -> { - final CharSequence charSeqText = view.getText(); - if (charSeqText != null && view.getLineCount() > maxLines) { - // Note that converting to String removes spans (i.e. links), but that's something - // we actually want since when the text is ellipsized we want all clicks on the - // comment to expand the comment, not to open links. - final String text = charSeqText.toString(); - - final Layout layout = view.getLayout(); - final float lineWidth = layout.getLineWidth(maxLines - 1); - final float layoutWidth = layout.getWidth(); - final int lineStart = layout.getLineStart(maxLines - 1); - final int lineEnd = layout.getLineEnd(maxLines - 1); - - // remove characters up until there is enough space for the ellipsis - // (also summing 2 more pixels, just to be sure to avoid float rounding errors) - int end = lineEnd; - float removedCharactersWidth = 0.0f; - while (lineWidth - removedCharactersWidth + ellipsisWidthPx + 2.0f > layoutWidth - && end >= lineStart) { - end -= 1; - // recalculate each time to account for ligatures or other similar things - removedCharactersWidth = paintAtContentSize.measureText( - text.substring(end, lineEnd)); - } - - // remove trailing spaces and newlines - while (end > 0 && Character.isWhitespace(text.charAt(end - 1))) { - end -= 1; - } - - final String newVal = text.substring(0, end) + ELLIPSIS; - view.setText(newVal); - isEllipsized = true; - } else { - isEllipsized = false; - } - view.setMaxLines(maxLines); - }); - } - - /** - * Toggle the view between the ellipsized and expanded state. - */ - public void toggle() { - if (isEllipsized) { - expand(); - } else { - ellipsize(); - } - } - - /** - * Whether the {@link #view} can be ellipsized. - * This is only the case when the {@link #content} has more lines - * than allowed via {@link #maxLines}. - * @return {@code true} if the {@link #content} has more lines than allowed via - * {@link #maxLines} and thus can be shortened, {@code false} if the {@code content} fits into - * the {@link #view} without being shortened and {@code null} if the initialization is not - * completed yet. - */ - @Nullable - public Boolean canBeEllipsized() { - return canBeEllipsized; - } - - private void linkifyContentView(final Consumer consumer) { - final boolean oldState = isEllipsized; - disposable.clear(); - TextLinkifier.fromDescription(view, content, - HtmlCompat.FROM_HTML_MODE_LEGACY, streamingService, streamUrl, disposable, - v -> { - consumer.accept(v); - notifyStateChangeListener(oldState); - }); - - } - - /** - * Add a listener which is called when the given content is changed, - * either from ellipsized to full or vice versa. - * @param listener The listener to be called, or {@code null} to remove it. - * The Boolean parameter is the new state. - * Ellipsized content is represented as {@code true}, - * normal or full content by {@code false}. - */ - public void setStateChangeListener(@Nullable final Consumer listener) { - this.stateChangeListener = listener; - } - - private void notifyStateChangeListener(final boolean oldState) { - if (oldState != isEllipsized && stateChangeListener != null) { - stateChangeListener.accept(isEllipsized); - } - } - -}