1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-02-17 04:00:48 +01:00

added text indices

This commit is contained in:
Mariotaku Lee 2016-05-29 10:27:19 +08:00
parent 5e0d4544a5
commit 180dac84d2
7 changed files with 99 additions and 75 deletions

View File

@ -543,6 +543,14 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
@JsonField(name = "user_statusnet_profile_url")
@ParcelableThisPlease
public String user_statusnet_profile_url;
@JsonField(name = "display_text_range")
@ParcelableThisPlease
@Nullable
public int[] display_text_range;
@JsonField(name = "quoted_display_text_range")
@ParcelableThisPlease
@Nullable
public int[] quoted_display_text_range;
@Override
public int describeContents() {

View File

@ -2,7 +2,6 @@ package org.mariotaku.twidere.model.util;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.text.Spannable;
import android.text.Spanned;
import android.text.TextUtils;
@ -90,10 +89,11 @@ public class ParcelableStatusUtils {
result.quoted_text_plain = result.quoted_text_unescaped;
result.quoted_spans = getSpanItems(html);
} else {
final Pair<String, SpanItem[]> textWithIndices = InternalTwitterContentUtils.formatStatusTextWithIndices(quoted);
final InternalTwitterContentUtils.StatusTextWithIndices textWithIndices = InternalTwitterContentUtils.formatStatusTextWithIndices(quoted);
result.quoted_text_plain = InternalTwitterContentUtils.unescapeTwitterStatusText(quotedText);
result.quoted_text_unescaped = textWithIndices.first;
result.quoted_spans = textWithIndices.second;
result.quoted_text_unescaped = textWithIndices.text;
result.quoted_spans = textWithIndices.spans;
result.extras.quoted_display_text_range = textWithIndices.range;
}
result.quoted_timestamp = quoted.getCreatedAt().getTime();
@ -157,10 +157,11 @@ public class ParcelableStatusUtils {
result.text_plain = result.text_unescaped;
result.spans = getSpanItems(html);
} else {
final Pair<String, SpanItem[]> textWithIndices = InternalTwitterContentUtils.formatStatusTextWithIndices(status);
result.text_unescaped = textWithIndices.first;
final InternalTwitterContentUtils.StatusTextWithIndices textWithIndices = InternalTwitterContentUtils.formatStatusTextWithIndices(status);
result.text_unescaped = textWithIndices.text;
result.text_plain = InternalTwitterContentUtils.unescapeTwitterStatusText(text);
result.spans = textWithIndices.second;
result.spans = textWithIndices.spans;
result.extras.display_text_range = textWithIndices.range;
}
result.media = ParcelableMediaUtils.fromStatus(status);
result.source = status.getSource();

View File

@ -45,8 +45,10 @@ public class ParcelableUserUtils implements TwidereConstants {
obj.screen_name = user.getScreenName();
obj.description_plain = user.getDescription();
final Pair<String, SpanItem[]> userDescription = InternalTwitterContentUtils.formatUserDescription(user);
obj.description_unescaped = userDescription.first;
obj.description_spans = userDescription.second;
if (userDescription != null) {
obj.description_unescaped = userDescription.first;
obj.description_spans = userDescription.second;
}
obj.location = user.getLocation();
obj.profile_image_url = TwitterContentUtils.getProfileImageUrl(user);
obj.profile_banner_url = user.getProfileBannerImageUrl();

View File

@ -88,4 +88,12 @@ public final class CodePointArray {
public String toString() {
return substring(0, length);
}
public int charCount(int start, int end) {
int count = 0;
for (int i = start; i < end; i++) {
count += Character.charCount(codePoints[i]);
}
return count;
}
}

View File

@ -236,25 +236,8 @@ public class InternalTwitterContentUtils {
return "ipad_retina";
}
public static String formatExpandedUserDescription(final User user) {
if (user == null) return null;
final String text = user.getDescription();
if (text == null) return null;
final HtmlBuilder builder = new HtmlBuilder(text, false, true, true);
final UrlEntity[] urls = user.getDescriptionEntities();
if (urls != null) {
for (final UrlEntity url : urls) {
final String expanded_url = url.getExpandedUrl();
if (expanded_url != null) {
builder.addLink(expanded_url, expanded_url, url.getStart(), url.getEnd());
}
}
}
return builder.buildWithIndices().first;
}
public static Pair<String, SpanItem[]> formatUserDescription(final User user) {
if (user == null) return null;
@Nullable
public static Pair<String, SpanItem[]> formatUserDescription(@NonNull final User user) {
final String text = user.getDescription();
if (text == null) return null;
final HtmlBuilder builder = new HtmlBuilder(text, false, true, true);
@ -270,20 +253,21 @@ public class InternalTwitterContentUtils {
return builder.buildWithIndices();
}
@Nullable
public static String unescapeTwitterStatusText(final CharSequence text) {
if (text == null) return null;
return UNESCAPE_TWITTER_RAW_TEXT.translate(text);
}
public static Pair<String, SpanItem[]> formatDirectMessageText(final DirectMessage message) {
if (message == null) return null;
@NonNull
public static Pair<String, SpanItem[]> formatDirectMessageText(@NonNull final DirectMessage message) {
final HtmlBuilder builder = new HtmlBuilder(message.getText(), false, true, true);
parseEntities(builder, message, null);
parseEntities(builder, message);
return builder.buildWithIndices();
}
public static Pair<String, SpanItem[]> formatStatusTextWithIndices(final Status status) {
if (status == null) return null;
@NonNull
public static StatusTextWithIndices formatStatusTextWithIndices(@NonNull final Status status) {
//TODO handle twitter video url
String text = status.getFullText();
@ -294,23 +278,35 @@ public class InternalTwitterContentUtils {
source = new CodePointArray(text);
} else {
range = status.getDisplayTextRange();
if (range != null && range.length == 2) {
source = new CodePointArray(text).subCodePointArray(range[0], range[1]);
} else {
range = null;
source = new CodePointArray(text);
}
source = new CodePointArray(text);
}
final HtmlBuilder builder = new HtmlBuilder(source, false, true, false);
parseEntities(builder, status, range);
return builder.buildWithIndices();
parseEntities(builder, status);
StatusTextWithIndices textWithIndices = new StatusTextWithIndices();
final Pair<String, SpanItem[]> pair = builder.buildWithIndices();
textWithIndices.text = pair.first;
textWithIndices.spans = pair.second;
if (range != null && range.length == 2) {
final int length = source.length();
textWithIndices.range = new int[2];
textWithIndices.range[0] = source.charCount(0, range[0]);
textWithIndices.range[1] = pair.first.length() - source.charCount(range[1], length);
}
return textWithIndices;
}
public static class StatusTextWithIndices {
public String text;
public SpanItem[] spans;
@Nullable
public int[] range;
}
public static String getMediaUrl(MediaEntity entity) {
return TextUtils.isEmpty(entity.getMediaUrlHttps()) ? entity.getMediaUrl() : entity.getMediaUrlHttps();
}
private static void parseEntities(final HtmlBuilder builder, final EntitySupport entities, @Nullable int[] range) {
private static void parseEntities(final HtmlBuilder builder, final EntitySupport entities) {
// Format media.
MediaEntity[] mediaEntities = null;
if (entities instanceof ExtendedEntitySupport) {
@ -323,7 +319,7 @@ public class InternalTwitterContentUtils {
if (mediaEntities != null) {
for (final MediaEntity mediaEntity : mediaEntities) {
final String mediaUrl = getMediaUrl(mediaEntity);
if (mediaUrl != null && getStartEndForEntity(mediaEntity, range, startEnd)) {
if (mediaUrl != null && getStartEndForEntity(mediaEntity, startEnd)) {
builder.addLink(mediaEntity.getExpandedUrl(), mediaEntity.getDisplayUrl(),
startEnd[0], startEnd[1]);
}
@ -333,7 +329,7 @@ public class InternalTwitterContentUtils {
if (urlEntities != null) {
for (final UrlEntity urlEntity : urlEntities) {
final String expandedUrl = urlEntity.getExpandedUrl();
if (expandedUrl != null && getStartEndForEntity(urlEntity, range, startEnd)) {
if (expandedUrl != null && getStartEndForEntity(urlEntity, startEnd)) {
builder.addLink(expandedUrl, urlEntity.getDisplayUrl(), startEnd[0],
startEnd[1]);
}
@ -341,17 +337,9 @@ public class InternalTwitterContentUtils {
}
}
private static boolean getStartEndForEntity(UrlEntity entity, @Nullable int[] range,
@NonNull int[] out) {
int offset = 0;
if (range != null) {
offset = range[0];
}
out[0] = entity.getStart() - offset;
out[1] = entity.getEnd() - offset;
if (range != null) {
return out[0] >= 0 && out[1] <= range[1] && out[0] <= out[1];
}
private static boolean getStartEndForEntity(UrlEntity entity, @NonNull int[] out) {
out[0] = entity.getStart();
out[1] = entity.getEnd();
return true;
}

View File

@ -272,15 +272,23 @@ public class StatusViewHolder extends ViewHolder implements Constants, IStatusVi
status.quoted_user_name));
quotedNameView.setScreenName("@" + status.quoted_user_screen_name);
int quotedDisplayEnd = -1;
if (status.extras.quoted_display_text_range != null) {
quotedDisplayEnd = status.extras.quoted_display_text_range[1];
}
final CharSequence text;
if (adapter.getLinkHighlightingStyle() != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
final SpannableStringBuilder text = SpannableStringBuilder.valueOf(status.quoted_text_unescaped);
ParcelableStatusUtils.applySpans(text, status.quoted_spans);
linkify.applyAllLinks(text, status.account_key, getLayoutPosition(),
text = SpannableStringBuilder.valueOf(status.quoted_text_unescaped);
ParcelableStatusUtils.applySpans((Spannable) text, status.quoted_spans);
linkify.applyAllLinks((Spannable) text, status.account_key, getLayoutPosition(),
status.is_possibly_sensitive, adapter.getLinkHighlightingStyle(),
skipLinksInText);
quotedTextView.setText(text);
} else {
final String text = status.quoted_text_unescaped;
text = status.quoted_text_unescaped;
}
if (quotedDisplayEnd != -1 && quotedDisplayEnd <= text.length()) {
quotedTextView.setText(text.subSequence(0, quotedDisplayEnd));
} else {
quotedTextView.setText(text);
}
@ -426,15 +434,25 @@ public class StatusViewHolder extends ViewHolder implements Constants, IStatusVi
}
}
int displayEnd = -1;
if (status.extras.display_text_range != null) {
displayEnd = status.extras.display_text_range[1];
}
final CharSequence text;
if (adapter.getLinkHighlightingStyle() != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
final SpannableStringBuilder text = SpannableStringBuilder.valueOf(status.text_unescaped);
ParcelableStatusUtils.applySpans(text, status.spans);
linkify.applyAllLinks(text, status.account_key, getLayoutPosition(),
text = SpannableStringBuilder.valueOf(status.text_unescaped);
ParcelableStatusUtils.applySpans((Spannable) text, status.spans);
linkify.applyAllLinks((Spannable) text, status.account_key, getLayoutPosition(),
status.is_possibly_sensitive, adapter.getLinkHighlightingStyle(),
skipLinksInText);
textView.setText(text);
} else {
textView.setText(status.text_unescaped);
text = status.text_unescaped;
}
if (displayEnd != -1 && displayEnd <= text.length()) {
textView.setText(text.subSequence(0, displayEnd));
} else {
textView.setText(text);
}
if (replyCount > 0) {

View File

@ -22,8 +22,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:background="?cardItemBackgroundColor">
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
@ -173,7 +172,7 @@
tools:text="@string/sample_status_text"
tools:visibility="visible"/>
<TextView
<org.mariotaku.twidere.view.ActionIconThemedTextView
android:id="@+id/media_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -183,9 +182,9 @@
android:layout_alignStart="@+id/text"
android:layout_below="@+id/text"
android:layout_marginTop="@dimen/element_spacing_xsmall"
android:gravity="center"
android:minHeight="@dimen/element_size_normal"
android:padding="@dimen/element_spacing_normal"
android:drawableLeft="@drawable/ic_action_gallery"
android:drawableStart="@drawable/ic_action_gallery"
android:gravity="center_vertical"
android:text="@string/media"
android:textAppearance="?android:textAppearanceSmall"
android:textStyle="bold"/>
@ -254,7 +253,7 @@
tools:text="@string/sample_status_text"
tools:visibility="visible"/>
<TextView
<org.mariotaku.twidere.view.ActionIconThemedTextView
android:id="@+id/quoted_media_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -262,9 +261,9 @@
android:layout_marginTop="@dimen/element_spacing_xsmall"
android:layout_toEndOf="@+id/quote_indicator"
android:layout_toRightOf="@+id/quote_indicator"
android:gravity="center"
android:minHeight="@dimen/element_size_normal"
android:padding="@dimen/element_spacing_normal"
android:drawableLeft="@drawable/ic_action_gallery"
android:drawableStart="@drawable/ic_action_gallery"
android:gravity="center_vertical"
android:text="@string/media"
android:textAppearance="?android:textAppearanceSmall"
android:textStyle="bold"/>