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

updated version

This commit is contained in:
Mariotaku Lee 2016-05-28 01:32:43 +08:00
parent 183a2ae752
commit 5e0d4544a5
16 changed files with 207 additions and 205 deletions

View File

@ -33,15 +33,19 @@ import org.mariotaku.library.objectcursor.annotation.CursorField;
import org.mariotaku.library.objectcursor.annotation.CursorObject; import org.mariotaku.library.objectcursor.annotation.CursorObject;
import org.mariotaku.twidere.model.util.UserKeyConverter; import org.mariotaku.twidere.model.util.UserKeyConverter;
import org.mariotaku.twidere.model.util.UserKeyCursorFieldConverter; import org.mariotaku.twidere.model.util.UserKeyCursorFieldConverter;
import org.mariotaku.twidere.provider.TwidereDataStore;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages; import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
import java.util.Arrays; import java.util.Arrays;
@ParcelablePlease(allFields = false) @ParcelablePlease(allFields = false)
@JsonObject @JsonObject
@CursorObject(valuesCreator = true) @CursorObject(valuesCreator = true, tableInfo = true)
public class ParcelableDirectMessage implements Parcelable, Comparable<ParcelableDirectMessage> { public class ParcelableDirectMessage implements Parcelable, Comparable<ParcelableDirectMessage> {
@ParcelableThisPlease
@CursorField(value = DirectMessages._ID, type = TwidereDataStore.TYPE_PRIMARY_KEY, excludeWrite = true)
public long _id;
@ParcelableThisPlease @ParcelableThisPlease
@JsonField(name = "account_id", typeConverter = UserKeyConverter.class) @JsonField(name = "account_id", typeConverter = UserKeyConverter.class)
@CursorField(value = DirectMessages.ACCOUNT_KEY, converter = UserKeyCursorFieldConverter.class) @CursorField(value = DirectMessages.ACCOUNT_KEY, converter = UserKeyCursorFieldConverter.class)
@ -70,17 +74,18 @@ public class ParcelableDirectMessage implements Parcelable, Comparable<Parcelabl
public boolean is_outgoing; public boolean is_outgoing;
@ParcelableThisPlease @ParcelableThisPlease
@JsonField(name = "text_html") @JsonField(name = "text_unescaped")
@CursorField(DirectMessages.TEXT_HTML) @CursorField(DirectMessages.TEXT_UNESCAPED)
public String text_html; public String text_unescaped;
@ParcelableThisPlease @ParcelableThisPlease
@JsonField(name = "text_plain") @JsonField(name = "text_plain")
@CursorField(DirectMessages.TEXT_PLAIN) @CursorField(DirectMessages.TEXT_PLAIN)
public String text_plain; public String text_plain;
@ParcelableThisPlease @ParcelableThisPlease
@JsonField(name = "text_unescaped") @JsonField(name = "spans")
@CursorField(DirectMessages.TEXT_UNESCAPED) @CursorField(value = DirectMessages.SPANS, converter = LoganSquareCursorFieldConverter.class)
public String text_unescaped; public SpanItem[] spans;
@ParcelableThisPlease @ParcelableThisPlease
@JsonField(name = "sender_name") @JsonField(name = "sender_name")
@ -108,6 +113,11 @@ public class ParcelableDirectMessage implements Parcelable, Comparable<Parcelabl
@CursorField(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL) @CursorField(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL)
public String recipient_profile_image_url; public String recipient_profile_image_url;
@ParcelableThisPlease
@JsonField(name = "conversation_id")
@CursorField(DirectMessages.CONVERSATION_ID)
public String conversation_id;
@ParcelableThisPlease @ParcelableThisPlease
@JsonField(name = "media") @JsonField(name = "media")
@CursorField(value = DirectMessages.MEDIA_JSON, converter = LoganSquareCursorFieldConverter.class) @CursorField(value = DirectMessages.MEDIA_JSON, converter = LoganSquareCursorFieldConverter.class)
@ -147,14 +157,14 @@ public class ParcelableDirectMessage implements Parcelable, Comparable<Parcelabl
public String toString() { public String toString() {
return "ParcelableDirectMessage{" + return "ParcelableDirectMessage{" +
"account_key=" + account_key + "account_key=" + account_key +
", id=" + id + ", id='" + id + '\'' +
", timestamp=" + timestamp + ", timestamp=" + timestamp +
", sender_id=" + sender_id + ", sender_id='" + sender_id + '\'' +
", recipient_id=" + recipient_id + ", recipient_id='" + recipient_id + '\'' +
", is_outgoing=" + is_outgoing + ", is_outgoing=" + is_outgoing +
", text_html='" + text_html + '\'' +
", text_plain='" + text_plain + '\'' +
", text_unescaped='" + text_unescaped + '\'' + ", text_unescaped='" + text_unescaped + '\'' +
", text_plain='" + text_plain + '\'' +
", spans=" + Arrays.toString(spans) +
", sender_name='" + sender_name + '\'' + ", sender_name='" + sender_name + '\'' +
", recipient_name='" + recipient_name + '\'' + ", recipient_name='" + recipient_name + '\'' +
", sender_screen_name='" + sender_screen_name + '\'' + ", sender_screen_name='" + sender_screen_name + '\'' +

View File

@ -32,10 +32,14 @@ import org.mariotaku.commons.objectcursor.LoganSquareCursorFieldConverter;
import org.mariotaku.library.objectcursor.annotation.AfterCursorObjectCreated; import org.mariotaku.library.objectcursor.annotation.AfterCursorObjectCreated;
import org.mariotaku.library.objectcursor.annotation.CursorField; import org.mariotaku.library.objectcursor.annotation.CursorField;
import org.mariotaku.library.objectcursor.annotation.CursorObject; import org.mariotaku.library.objectcursor.annotation.CursorObject;
import org.mariotaku.microblog.library.twitter.model.DirectMessage;
import org.mariotaku.twidere.model.util.UserKeyConverter; import org.mariotaku.twidere.model.util.UserKeyConverter;
import org.mariotaku.twidere.model.util.UserKeyCursorFieldConverter; import org.mariotaku.twidere.model.util.UserKeyCursorFieldConverter;
import org.mariotaku.twidere.provider.TwidereDataStore;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers; import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
import java.util.Arrays;
@ParcelablePlease(allFields = false) @ParcelablePlease(allFields = false)
@JsonObject @JsonObject
@ -114,17 +118,14 @@ public class ParcelableUser implements Parcelable, Comparable<ParcelableUser> {
@CursorField(CachedUsers.URL_EXPANDED) @CursorField(CachedUsers.URL_EXPANDED)
public String url_expanded; public String url_expanded;
@ParcelableThisPlease @ParcelableThisPlease
@JsonField(name = "description_html")
@CursorField(CachedUsers.DESCRIPTION_HTML)
public String description_html;
@ParcelableThisPlease
@JsonField(name = "description_unescaped") @JsonField(name = "description_unescaped")
@CursorField(CachedUsers.DESCRIPTION_UNESCAPED) @CursorField(CachedUsers.DESCRIPTION_UNESCAPED)
public String description_unescaped; public String description_unescaped;
@ParcelableThisPlease @ParcelableThisPlease
@JsonField(name = "description_expanded") @JsonField(name = "description_spans")
@CursorField(CachedUsers.DESCRIPTION_EXPANDED) @CursorField(value = CachedUsers.DESCRIPTION_SPANS, converter = LoganSquareCursorFieldConverter.class)
public String description_expanded; public SpanItem[] description_spans;
@ParcelableThisPlease @ParcelableThisPlease
@JsonField(name = "followers_count") @JsonField(name = "followers_count")
@ -272,9 +273,8 @@ public class ParcelableUser implements Parcelable, Comparable<ParcelableUser> {
", profile_background_url='" + profile_background_url + '\'' + ", profile_background_url='" + profile_background_url + '\'' +
", url='" + url + '\'' + ", url='" + url + '\'' +
", url_expanded='" + url_expanded + '\'' + ", url_expanded='" + url_expanded + '\'' +
", description_html='" + description_html + '\'' +
", description_unescaped='" + description_unescaped + '\'' + ", description_unescaped='" + description_unescaped + '\'' +
", description_expanded='" + description_expanded + '\'' + ", description_spans=" + Arrays.toString(description_spans) +
", followers_count=" + followers_count + ", followers_count=" + followers_count +
", friends_count=" + friends_count + ", friends_count=" + friends_count +
", statuses_count=" + statuses_count + ", statuses_count=" + statuses_count +

View File

@ -24,6 +24,7 @@ import android.net.Uri;
import android.provider.BaseColumns; import android.provider.BaseColumns;
import org.mariotaku.twidere.model.ParcelableActivityTableInfo; import org.mariotaku.twidere.model.ParcelableActivityTableInfo;
import org.mariotaku.twidere.model.ParcelableDirectMessageTableInfo;
import org.mariotaku.twidere.model.ParcelableStatusTableInfo; import org.mariotaku.twidere.model.ParcelableStatusTableInfo;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -252,11 +253,9 @@ public interface TwidereDataStore {
String DESCRIPTION_PLAIN = "description_plain"; String DESCRIPTION_PLAIN = "description_plain";
String DESCRIPTION_HTML = "description_html";
String DESCRIPTION_UNESCAPED = "description_unescaped"; String DESCRIPTION_UNESCAPED = "description_unescaped";
String DESCRIPTION_EXPANDED = "description_expanded"; String DESCRIPTION_SPANS = "description_spans";
String LOCATION = "location"; String LOCATION = "location";
@ -306,7 +305,7 @@ public interface TwidereDataStore {
String[] COLUMNS = {_ID, USER_KEY, CREATED_AT, NAME, SCREEN_NAME, DESCRIPTION_PLAIN, LOCATION, String[] COLUMNS = {_ID, USER_KEY, CREATED_AT, NAME, SCREEN_NAME, DESCRIPTION_PLAIN, LOCATION,
URL, PROFILE_IMAGE_URL, PROFILE_BANNER_URL, PROFILE_BACKGROUND_URL, IS_PROTECTED, URL, PROFILE_IMAGE_URL, PROFILE_BANNER_URL, PROFILE_BACKGROUND_URL, IS_PROTECTED,
IS_VERIFIED, IS_FOLLOWING, FOLLOWERS_COUNT, FRIENDS_COUNT, STATUSES_COUNT, IS_VERIFIED, IS_FOLLOWING, FOLLOWERS_COUNT, FRIENDS_COUNT, STATUSES_COUNT,
FAVORITES_COUNT, LISTED_COUNT, MEDIA_COUNT, DESCRIPTION_HTML, DESCRIPTION_EXPANDED, FAVORITES_COUNT, LISTED_COUNT, MEDIA_COUNT, DESCRIPTION_SPANS,
URL_EXPANDED, BACKGROUND_COLOR, LINK_COLOR, TEXT_COLOR, LAST_SEEN, URL_EXPANDED, BACKGROUND_COLOR, LINK_COLOR, TEXT_COLOR, LAST_SEEN,
DESCRIPTION_UNESCAPED, EXTRAS}; DESCRIPTION_UNESCAPED, EXTRAS};
@ -315,7 +314,7 @@ public interface TwidereDataStore {
String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_TEXT_NOT_NULL, TYPE_INT, TYPE_TEXT, TYPE_TEXT, String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_TEXT_NOT_NULL, TYPE_INT, TYPE_TEXT, TYPE_TEXT,
TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_BOOLEAN, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_BOOLEAN,
TYPE_BOOLEAN, TYPE_BOOLEAN, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_BOOLEAN, TYPE_BOOLEAN, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
TYPE_INT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_TEXT, TYPE_TEXT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
TYPE_TEXT, TYPE_TEXT}; TYPE_TEXT, TYPE_TEXT};
} }
@ -404,9 +403,9 @@ public interface TwidereDataStore {
String IS_OUTGOING = "is_outgoing"; String IS_OUTGOING = "is_outgoing";
String TEXT_HTML = "text_html";
String TEXT_PLAIN = "text_plain"; String TEXT_PLAIN = "text_plain";
String TEXT_UNESCAPED = "text_unescaped"; String TEXT_UNESCAPED = "text_unescaped";
String SPANS = "spans";
String SENDER_NAME = "sender_name"; String SENDER_NAME = "sender_name";
String RECIPIENT_NAME = "recipient_name"; String RECIPIENT_NAME = "recipient_name";
String SENDER_SCREEN_NAME = "sender_screen_name"; String SENDER_SCREEN_NAME = "sender_screen_name";
@ -416,13 +415,8 @@ public interface TwidereDataStore {
String MEDIA_JSON = "media_json"; String MEDIA_JSON = "media_json";
String[] COLUMNS = {_ID, ACCOUNT_KEY, MESSAGE_ID, MESSAGE_TIMESTAMP, String[] COLUMNS = ParcelableDirectMessageTableInfo.COLUMNS;
SENDER_ID, RECIPIENT_ID, CONVERSATION_ID, IS_OUTGOING, TEXT_HTML, TEXT_PLAIN, TEXT_UNESCAPED, String[] TYPES = ParcelableDirectMessageTableInfo.TYPES;
SENDER_NAME, RECIPIENT_NAME, SENDER_SCREEN_NAME, RECIPIENT_SCREEN_NAME, SENDER_PROFILE_IMAGE_URL,
RECIPIENT_PROFILE_IMAGE_URL, MEDIA_JSON, INSERTED_DATE};
String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_TEXT_NOT_NULL, TYPE_TEXT_NOT_NULL, TYPE_INT,
TYPE_TEXT_NOT_NULL, TYPE_TEXT_NOT_NULL, TYPE_INT, TYPE_BOOLEAN, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT,
TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, INSERTED_DATE_TYPE};
String DEFAULT_SORT_ORDER = MESSAGE_ID + " DESC"; String DEFAULT_SORT_ORDER = MESSAGE_ID + " DESC";
@ -460,7 +454,7 @@ public interface TwidereDataStore {
String NAME = "name"; String NAME = "name";
String SCREEN_NAME = "screen_name"; String SCREEN_NAME = "screen_name";
String PROFILE_IMAGE_URL = "profile_image_url"; String PROFILE_IMAGE_URL = "profile_image_url";
String TEXT_HTML = DirectMessages.TEXT_HTML; String TEXT_UNESCAPED = "text_unescaped";
String CONVERSATION_ID = "conversation_id"; String CONVERSATION_ID = "conversation_id";
int IDX__ID = 0; int IDX__ID = 0;
@ -471,7 +465,7 @@ public interface TwidereDataStore {
int IDX_NAME = 5; int IDX_NAME = 5;
int IDX_SCREEN_NAME = 6; int IDX_SCREEN_NAME = 6;
int IDX_PROFILE_IMAGE_URL = 7; int IDX_PROFILE_IMAGE_URL = 7;
int IDX_TEXT = 8; int IDX_TEXT_UNESCAPED = 8;
int IDX_CONVERSATION_ID = 9; int IDX_CONVERSATION_ID = 9;
} }

View File

@ -34,7 +34,7 @@ import static org.mariotaku.twidere.annotation.PreferenceType.STRING;
public interface Constants extends TwidereConstants { public interface Constants extends TwidereConstants {
String DATABASES_NAME = "twidere.sqlite"; String DATABASES_NAME = "twidere.sqlite";
int DATABASES_VERSION = 145; int DATABASES_VERSION = 150;
int MENU_GROUP_STATUS_EXTENSION = 10; int MENU_GROUP_STATUS_EXTENSION = 10;
int MENU_GROUP_COMPOSE_EXTENSION = 11; int MENU_GROUP_COMPOSE_EXTENSION = 11;

View File

@ -58,7 +58,7 @@ import android.support.v4.view.WindowCompat;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.text.Spannable; import android.text.SpannableStringBuilder;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.util.Linkify; import android.text.util.Linkify;
import android.util.Log; import android.util.Log;
@ -125,6 +125,7 @@ import org.mariotaku.twidere.model.message.TaskStateChangedEvent;
import org.mariotaku.twidere.model.util.ParcelableAccountUtils; import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils; import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils;
import org.mariotaku.twidere.model.util.ParcelableMediaUtils; import org.mariotaku.twidere.model.util.ParcelableMediaUtils;
import org.mariotaku.twidere.model.util.ParcelableStatusUtils;
import org.mariotaku.twidere.model.util.ParcelableUserUtils; import org.mariotaku.twidere.model.util.ParcelableUserUtils;
import org.mariotaku.twidere.model.util.UserKeyUtils; import org.mariotaku.twidere.model.util.UserKeyUtils;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships; import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships;
@ -133,7 +134,6 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
import org.mariotaku.twidere.util.AsyncTwitterWrapper; import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ContentValuesCreator; import org.mariotaku.twidere.util.ContentValuesCreator;
import org.mariotaku.twidere.util.DataStoreUtils; import org.mariotaku.twidere.util.DataStoreUtils;
import org.mariotaku.twidere.util.HtmlSpanBuilder;
import org.mariotaku.twidere.util.IntentUtils; import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.InternalTwitterContentUtils; import org.mariotaku.twidere.util.InternalTwitterContentUtils;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler; import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
@ -553,16 +553,17 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mProfileTypeView.setVisibility(View.GONE); mProfileTypeView.setVisibility(View.GONE);
} }
mScreenNameView.setText(String.format("@%s", user.screen_name)); mScreenNameView.setText(String.format("@%s", user.screen_name));
mDescriptionContainer.setVisibility(TextUtils.isEmpty(user.description_html) ? View.GONE : View.VISIBLE);
final TwidereLinkify linkify = new TwidereLinkify(this); final TwidereLinkify linkify = new TwidereLinkify(this);
if (user.description_html != null) { if (user.description_unescaped != null) {
final Spannable text = HtmlSpanBuilder.fromHtml(user.description_html); final SpannableStringBuilder text = SpannableStringBuilder.valueOf(user.description_unescaped);
ParcelableStatusUtils.applySpans(text, user.description_spans);
linkify.applyAllLinks(text, user.account_key, false, false); linkify.applyAllLinks(text, user.account_key, false, false);
mDescriptionView.setText(text); mDescriptionView.setText(text);
} else { } else {
mDescriptionView.setText(user.description_plain); mDescriptionView.setText(user.description_plain);
Linkify.addLinks(mDescriptionView, Linkify.WEB_URLS); Linkify.addLinks(mDescriptionView, Linkify.WEB_URLS);
} }
mDescriptionContainer.setVisibility(mDescriptionView.length() > 0 ? View.VISIBLE : View.GONE);
mLocationContainer.setVisibility(TextUtils.isEmpty(user.location) ? View.GONE : View.VISIBLE); mLocationContainer.setVisibility(TextUtils.isEmpty(user.location) ? View.GONE : View.VISIBLE);
mLocationView.setText(user.location); mLocationView.setText(user.location);

View File

@ -258,7 +258,7 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
displayUser(user); displayUser(user);
mEditName.setText(savedInstanceState.getString(EXTRA_NAME, user.name)); mEditName.setText(savedInstanceState.getString(EXTRA_NAME, user.name));
mEditLocation.setText(savedInstanceState.getString(EXTRA_LOCATION, user.location)); mEditLocation.setText(savedInstanceState.getString(EXTRA_LOCATION, user.location));
mEditDescription.setText(savedInstanceState.getString(EXTRA_DESCRIPTION, user.description_expanded)); mEditDescription.setText(savedInstanceState.getString(EXTRA_DESCRIPTION, ParcelableUserUtils.getExpandedDescription(user)));
mEditUrl.setText(savedInstanceState.getString(EXTRA_URL, user.url_expanded)); mEditUrl.setText(savedInstanceState.getString(EXTRA_URL, user.url_expanded));
} else { } else {
getUserInfo(); getUserInfo();
@ -359,7 +359,7 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
mProgressContainer.setVisibility(View.GONE); mProgressContainer.setVisibility(View.GONE);
mEditProfileContent.setVisibility(View.VISIBLE); mEditProfileContent.setVisibility(View.VISIBLE);
mEditName.setText(user.name); mEditName.setText(user.name);
mEditDescription.setText(user.description_expanded); mEditDescription.setText(ParcelableUserUtils.getExpandedDescription(user));
mEditLocation.setText(user.location); mEditLocation.setText(user.location);
mEditUrl.setText(isEmpty(user.url_expanded) ? user.url : user.url_expanded); mEditUrl.setText(isEmpty(user.url_expanded) ? user.url : user.url_expanded);
mMediaLoader.displayProfileImage(mProfileImageView, user); mMediaLoader.displayProfileImage(mProfileImageView, user);
@ -515,7 +515,7 @@ public class UserProfileEditorFragment extends BaseSupportFragment implements On
if (mLinkColor != orig.link_color) return true; if (mLinkColor != orig.link_color) return true;
if (mBackgroundColor != orig.background_color) return true; if (mBackgroundColor != orig.background_color) return true;
if (!stringEquals(mName, orig.name)) return true; if (!stringEquals(mName, orig.name)) return true;
if (!stringEquals(mDescription, isEmpty(orig.description_expanded) ? orig.description_plain : orig.description_expanded)) if (!stringEquals(mDescription, ParcelableUserUtils.getExpandedDescription(orig)))
return true; return true;
if (!stringEquals(mLocation, orig.location)) return true; if (!stringEquals(mLocation, orig.location)) return true;
if (!stringEquals(mUrl, isEmpty(orig.url_expanded) ? orig.url : orig.url_expanded)) if (!stringEquals(mUrl, isEmpty(orig.url_expanded) ? orig.url : orig.url_expanded))

View File

@ -1,16 +1,17 @@
package org.mariotaku.twidere.model.util; package org.mariotaku.twidere.model.util;
import android.support.v4.util.Pair;
import org.mariotaku.microblog.library.twitter.model.DirectMessage; import org.mariotaku.microblog.library.twitter.model.DirectMessage;
import org.mariotaku.microblog.library.twitter.model.User; import org.mariotaku.microblog.library.twitter.model.User;
import org.mariotaku.twidere.model.ParcelableDirectMessage; import org.mariotaku.twidere.model.ParcelableDirectMessage;
import org.mariotaku.twidere.model.SpanItem;
import org.mariotaku.twidere.model.UserKey; import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.util.InternalTwitterContentUtils; import org.mariotaku.twidere.util.InternalTwitterContentUtils;
import org.mariotaku.twidere.util.TwitterContentUtils; import org.mariotaku.twidere.util.TwitterContentUtils;
import java.util.Date; import java.util.Date;
import static org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText;
/** /**
* Created by mariotaku on 16/2/13. * Created by mariotaku on 16/2/13.
*/ */
@ -31,7 +32,9 @@ public class ParcelableDirectMessageUtils {
result.timestamp = getTime(message.getCreatedAt()); result.timestamp = getTime(message.getCreatedAt());
result.sender_id = sender.getId(); result.sender_id = sender.getId();
result.recipient_id = recipient.getId(); result.recipient_id = recipient.getId();
result.text_html = InternalTwitterContentUtils.formatDirectMessageText(message); final Pair<String, SpanItem[]> pair = InternalTwitterContentUtils.formatDirectMessageText(message);
result.text_unescaped = pair.first;
result.spans = pair.second;
result.text_plain = message.getText(); result.text_plain = message.getText();
result.sender_name = sender.getName(); result.sender_name = sender.getName();
result.recipient_name = recipient.getName(); result.recipient_name = recipient.getName();
@ -39,8 +42,12 @@ public class ParcelableDirectMessageUtils {
result.recipient_screen_name = recipient.getScreenName(); result.recipient_screen_name = recipient.getScreenName();
result.sender_profile_image_url = sender_profile_image_url; result.sender_profile_image_url = sender_profile_image_url;
result.recipient_profile_image_url = recipient_profile_image_url; result.recipient_profile_image_url = recipient_profile_image_url;
result.text_unescaped = toPlainText(result.text_html);
result.media = ParcelableMediaUtils.fromEntities(message); result.media = ParcelableMediaUtils.fromEntities(message);
if (isOutgoing) {
result.conversation_id = result.recipient_id;
} else {
result.conversation_id = result.sender_id;
}
return result; return result;
} }

View File

@ -3,7 +3,7 @@ package org.mariotaku.twidere.model.util;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.util.Pair; import android.support.v4.util.Pair;
import android.text.SpannableStringBuilder; import android.text.Spannable;
import android.text.Spanned; import android.text.Spanned;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.style.URLSpan; import android.text.style.URLSpan;
@ -25,7 +25,6 @@ import org.mariotaku.twidere.util.TwitterContentUtils;
import org.mariotaku.twidere.util.UserColorNameManager; import org.mariotaku.twidere.util.UserColorNameManager;
import java.util.Date; import java.util.Date;
import java.util.List;
import static org.mariotaku.twidere.TwidereConstants.USER_TYPE_FANFOU_COM; import static org.mariotaku.twidere.TwidereConstants.USER_TYPE_FANFOU_COM;
@ -91,10 +90,10 @@ public class ParcelableStatusUtils {
result.quoted_text_plain = result.quoted_text_unescaped; result.quoted_text_plain = result.quoted_text_unescaped;
result.quoted_spans = getSpanItems(html); result.quoted_spans = getSpanItems(html);
} else { } else {
final Pair<String, List<SpanItem>> textWithIndices = InternalTwitterContentUtils.formatStatusTextWithIndices(quoted); final Pair<String, SpanItem[]> textWithIndices = InternalTwitterContentUtils.formatStatusTextWithIndices(quoted);
result.quoted_text_plain = InternalTwitterContentUtils.unescapeTwitterStatusText(quotedText); result.quoted_text_plain = InternalTwitterContentUtils.unescapeTwitterStatusText(quotedText);
result.quoted_text_unescaped = textWithIndices.first; result.quoted_text_unescaped = textWithIndices.first;
result.quoted_spans = textWithIndices.second.toArray(new SpanItem[textWithIndices.second.size()]); result.quoted_spans = textWithIndices.second;
} }
result.quoted_timestamp = quoted.getCreatedAt().getTime(); result.quoted_timestamp = quoted.getCreatedAt().getTime();
@ -158,10 +157,10 @@ public class ParcelableStatusUtils {
result.text_plain = result.text_unescaped; result.text_plain = result.text_unescaped;
result.spans = getSpanItems(html); result.spans = getSpanItems(html);
} else { } else {
final Pair<String, List<SpanItem>> textWithIndices = InternalTwitterContentUtils.formatStatusTextWithIndices(status); final Pair<String, SpanItem[]> textWithIndices = InternalTwitterContentUtils.formatStatusTextWithIndices(status);
result.text_unescaped = textWithIndices.first; result.text_unescaped = textWithIndices.first;
result.text_plain = InternalTwitterContentUtils.unescapeTwitterStatusText(text); result.text_plain = InternalTwitterContentUtils.unescapeTwitterStatusText(text);
result.spans = textWithIndices.second.toArray(new SpanItem[textWithIndices.second.size()]); result.spans = textWithIndices.second;
} }
result.media = ParcelableMediaUtils.fromStatus(status); result.media = ParcelableMediaUtils.fromStatus(status);
result.source = status.getSource(); result.source = status.getSource();
@ -284,7 +283,7 @@ public class ParcelableStatusUtils {
return status.getInReplyToScreenName(); return status.getInReplyToScreenName();
} }
public static void applySpans(@NonNull SpannableStringBuilder text, @Nullable SpanItem[] spans) { public static void applySpans(@NonNull Spannable text, @Nullable SpanItem[] spans) {
if (spans == null) return; if (spans == null) return;
for (SpanItem span : spans) { for (SpanItem span : spans) {
text.setSpan(new URLSpan(span.link), span.start, span.end, text.setSpan(new URLSpan(span.link), span.start, span.end,

View File

@ -3,6 +3,7 @@ package org.mariotaku.twidere.model.util;
import android.database.Cursor; import android.database.Cursor;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.text.TextUtils; import android.text.TextUtils;
import org.mariotaku.microblog.library.twitter.model.UrlEntity; import org.mariotaku.microblog.library.twitter.model.UrlEntity;
@ -10,9 +11,9 @@ import org.mariotaku.microblog.library.twitter.model.User;
import org.mariotaku.twidere.TwidereConstants; import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.model.ParcelableAccount; import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableUser; import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.SpanItem;
import org.mariotaku.twidere.model.UserKey; import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages; import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
import org.mariotaku.twidere.util.HtmlEscapeHelper;
import org.mariotaku.twidere.util.InternalTwitterContentUtils; import org.mariotaku.twidere.util.InternalTwitterContentUtils;
import org.mariotaku.twidere.util.ParseUtils; import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.TwitterContentUtils; import org.mariotaku.twidere.util.TwitterContentUtils;
@ -43,9 +44,9 @@ public class ParcelableUserUtils implements TwidereConstants {
obj.name = user.getName(); obj.name = user.getName();
obj.screen_name = user.getScreenName(); obj.screen_name = user.getScreenName();
obj.description_plain = user.getDescription(); obj.description_plain = user.getDescription();
obj.description_html = InternalTwitterContentUtils.formatUserDescription(user); final Pair<String, SpanItem[]> userDescription = InternalTwitterContentUtils.formatUserDescription(user);
obj.description_expanded = InternalTwitterContentUtils.formatExpandedUserDescription(user); obj.description_unescaped = userDescription.first;
obj.description_unescaped = HtmlEscapeHelper.toPlainText(obj.description_html); obj.description_spans = userDescription.second;
obj.location = user.getLocation(); obj.location = user.getLocation();
obj.profile_image_url = TwitterContentUtils.getProfileImageUrl(user); obj.profile_image_url = TwitterContentUtils.getProfileImageUrl(user);
obj.profile_banner_url = user.getProfileBannerImageUrl(); obj.profile_banner_url = user.getProfileBannerImageUrl();
@ -129,4 +130,14 @@ public class ParcelableUserUtils implements TwidereConstants {
user.color = manager.getUserColor(user.key); user.color = manager.getUserColor(user.key);
user.nickname = manager.getUserNickname(user.key); user.nickname = manager.getUserNickname(user.key);
} }
public static String getExpandedDescription(ParcelableUser user) {
if (TextUtils.isEmpty(user.description_unescaped)) {
return user.description_plain;
}
if (user.description_spans != null) {
// TODO expand description
}
return user.description_unescaped;
}
} }

View File

@ -38,7 +38,6 @@ import org.mariotaku.twidere.model.ParcelableActivityValuesCreator;
import org.mariotaku.twidere.model.ParcelableCredentials; import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableDirectMessage; import org.mariotaku.twidere.model.ParcelableDirectMessage;
import org.mariotaku.twidere.model.ParcelableDirectMessageValuesCreator; import org.mariotaku.twidere.model.ParcelableDirectMessageValuesCreator;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableMediaUpdate; import org.mariotaku.twidere.model.ParcelableMediaUpdate;
import org.mariotaku.twidere.model.ParcelableStatus; import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableStatusValuesCreator; import org.mariotaku.twidere.model.ParcelableStatusValuesCreator;
@ -48,11 +47,10 @@ import org.mariotaku.twidere.model.ParcelableUserValuesCreator;
import org.mariotaku.twidere.model.UserKey; import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtra; import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtra;
import org.mariotaku.twidere.model.util.ParcelableActivityUtils; import org.mariotaku.twidere.model.util.ParcelableActivityUtils;
import org.mariotaku.twidere.model.util.ParcelableMediaUtils; import org.mariotaku.twidere.model.util.ParcelableDirectMessageUtils;
import org.mariotaku.twidere.model.util.ParcelableStatusUtils; import org.mariotaku.twidere.model.util.ParcelableStatusUtils;
import org.mariotaku.twidere.model.util.ParcelableUserUtils; import org.mariotaku.twidere.model.util.ParcelableUserUtils;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends; import org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts; import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
import org.mariotaku.twidere.provider.TwidereDataStore.Filters; import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
import org.mariotaku.twidere.provider.TwidereDataStore.SavedSearches; import org.mariotaku.twidere.provider.TwidereDataStore.SavedSearches;
@ -82,37 +80,8 @@ public final class ContentValuesCreator implements TwidereConstants {
public static ContentValues createDirectMessage(final DirectMessage message, public static ContentValues createDirectMessage(final DirectMessage message,
final UserKey accountKey, final UserKey accountKey,
final boolean isOutgoing) { final boolean isOutgoing) {
if (message == null) return null; return ParcelableDirectMessageValuesCreator.create(ParcelableDirectMessageUtils.fromDirectMessage(message,
final ContentValues values = new ContentValues(); accountKey, isOutgoing));
final User sender = message.getSender(), recipient = message.getRecipient();
if (sender == null || recipient == null) return null;
final String sender_profile_image_url = TwitterContentUtils.getProfileImageUrl(sender);
final String recipient_profile_image_url = TwitterContentUtils.getProfileImageUrl(recipient);
values.put(DirectMessages.ACCOUNT_KEY, accountKey.toString());
values.put(DirectMessages.MESSAGE_ID, message.getId());
values.put(DirectMessages.MESSAGE_TIMESTAMP, message.getCreatedAt().getTime());
values.put(DirectMessages.SENDER_ID, sender.getId());
values.put(DirectMessages.RECIPIENT_ID, recipient.getId());
if (isOutgoing) {
values.put(DirectMessages.CONVERSATION_ID, recipient.getId());
} else {
values.put(DirectMessages.CONVERSATION_ID, sender.getId());
}
final String text_html = InternalTwitterContentUtils.formatDirectMessageText(message);
values.put(DirectMessages.TEXT_HTML, text_html);
values.put(DirectMessages.TEXT_PLAIN, message.getText());
values.put(DirectMessages.TEXT_UNESCAPED, HtmlEscapeHelper.toPlainText(text_html));
values.put(DirectMessages.IS_OUTGOING, isOutgoing);
values.put(DirectMessages.SENDER_NAME, sender.getName());
values.put(DirectMessages.SENDER_SCREEN_NAME, sender.getScreenName());
values.put(DirectMessages.RECIPIENT_NAME, recipient.getName());
values.put(DirectMessages.RECIPIENT_SCREEN_NAME, recipient.getScreenName());
values.put(DirectMessages.SENDER_PROFILE_IMAGE_URL, sender_profile_image_url);
values.put(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL, recipient_profile_image_url);
final ParcelableMedia[] mediaArray = ParcelableMediaUtils.fromEntities(message);
values.put(DirectMessages.MEDIA_JSON, JsonSerializer.serialize(Arrays.asList(mediaArray),
ParcelableMedia.class));
return values;
} }
public static ContentValues createDirectMessage(final ParcelableDirectMessage message) { public static ContentValues createDirectMessage(final ParcelableDirectMessage message) {

View File

@ -26,7 +26,6 @@ import org.mariotaku.twidere.model.SpanItem;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import static android.text.TextUtils.isEmpty; import static android.text.TextUtils.isEmpty;
@ -39,7 +38,7 @@ public class HtmlBuilder {
private final int sourceLength; private final int sourceLength;
private final boolean throwExceptions, sourceIsEscaped, shouldReEscape; private final boolean throwExceptions, sourceIsEscaped, shouldReEscape;
private final ArrayList<LinkSpec> links = new ArrayList<>(); private final ArrayList<SpanSpec> spanSpecs = new ArrayList<>();
public HtmlBuilder(final String source, final boolean strict, final boolean sourceIsEscaped, public HtmlBuilder(final String source, final boolean strict, final boolean sourceIsEscaped,
final boolean shouldReEscape) { final boolean shouldReEscape) {
@ -61,7 +60,7 @@ public class HtmlBuilder {
} }
public boolean addLink(final String link, final String display, final int start, final int end, public boolean addLink(final String link, final String display, final int start, final int end,
final boolean display_is_html) { final boolean displayIsHtml) {
if (start < 0 || end < 0 || start > end || end > sourceLength) { if (start < 0 || end < 0 || start > end || end > sourceLength) {
final String message = String.format(Locale.US, "text:%s, length:%d, start:%d, end:%d", source, final String message = String.format(Locale.US, "text:%s, length:%d, start:%d, end:%d", source,
sourceLength, start, end); sourceLength, start, end);
@ -75,83 +74,39 @@ public class HtmlBuilder {
if (throwExceptions) throw new IllegalArgumentException(message); if (throwExceptions) throw new IllegalArgumentException(message);
return false; return false;
} }
return links.add(new LinkSpec(link, display, start, end, display_is_html)); return spanSpecs.add(new LinkSpec(link, display, start, end, displayIsHtml));
} }
public String build() { public Pair<String, SpanItem[]> buildWithIndices() {
if (links.isEmpty()) return escapeSource(); if (spanSpecs.isEmpty()) return Pair.create(escapeSource(), new SpanItem[0]);
Collections.sort(links); Collections.sort(spanSpecs);
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
final int linksSize = links.size(); final int linksSize = spanSpecs.size();
SpanItem[] items = new SpanItem[linksSize];
for (int i = 0; i < linksSize; i++) { for (int i = 0; i < linksSize; i++) {
final LinkSpec spec = links.get(i); final SpanSpec spec = spanSpecs.get(i);
if (spec == null) { final int start = spec.getStart(), end = spec.getEnd();
continue;
}
final int start = spec.start, end = spec.end;
if (i == 0) {
if (start >= 0 && start <= sourceLength) {
appendSource(sb, 0, start, shouldReEscape, sourceIsEscaped);
}
} else if (i > 0) {
final int lastEnd = links.get(i - 1).end;
if (lastEnd >= 0 && lastEnd <= start && start <= sourceLength) {
appendSource(sb, lastEnd, start, shouldReEscape, sourceIsEscaped);
}
}
sb.append("<a href=\"");
sb.append(spec.link);
sb.append("\">");
if (start >= 0 && start <= end && end <= sourceLength) {
if (isEmpty(spec.display)) {
append(sb, spec.link, shouldReEscape, false);
} else {
append(sb, spec.display, shouldReEscape, spec.displayIsHtml);
}
}
sb.append("</a>");
if (i == linksSize - 1 && end >= 0 && end <= sourceLength) {
appendSource(sb, end, sourceLength, shouldReEscape, sourceIsEscaped);
}
}
return sb.toString();
}
public Pair<String, List<SpanItem>> buildWithIndices() {
List<SpanItem> items = new ArrayList<>();
if (links.isEmpty()) return Pair.create(escapeSource(), items);
Collections.sort(links);
final StringBuilder sb = new StringBuilder();
final int linksSize = links.size();
for (int i = 0; i < linksSize; i++) {
final LinkSpec spec = links.get(i);
if (spec == null) {
continue;
}
final int start = spec.start, end = spec.end;
if (i == 0) { if (i == 0) {
if (start >= 0 && start <= sourceLength) { if (start >= 0 && start <= sourceLength) {
appendSource(sb, 0, start, false, sourceIsEscaped); appendSource(sb, 0, start, false, sourceIsEscaped);
} }
} else if (i > 0) { } else if (i > 0) {
final int lastEnd = links.get(i - 1).end; final int lastEnd = spanSpecs.get(i - 1).end;
if (lastEnd >= 0 && lastEnd <= start && start <= sourceLength) { if (lastEnd >= 0 && lastEnd <= start && start <= sourceLength) {
appendSource(sb, lastEnd, start, false, sourceIsEscaped); appendSource(sb, lastEnd, start, false, sourceIsEscaped);
} }
} }
int spanStart = sb.length(); int spanStart = sb.length();
if (start >= 0 && start <= end && end <= sourceLength) { if (start >= 0 && start <= end && end <= sourceLength) {
if (isEmpty(spec.display)) { spec.appendTo(sb);
append(sb, spec.link, false, false);
} else {
append(sb, spec.display, false, spec.displayIsHtml);
}
} }
final SpanItem item = new SpanItem(); final SpanItem item = new SpanItem();
item.start = spanStart; item.start = spanStart;
item.end = sb.length(); item.end = sb.length();
item.link = spec.link; if (spec instanceof LinkSpec) {
items.add(item); item.link = ((LinkSpec) spec).link;
}
items[i] = item;
if (i == linksSize - 1 && end >= 0 && end <= sourceLength) { if (i == linksSize - 1 && end >= 0 && end <= sourceLength) {
appendSource(sb, end, sourceLength, false, sourceIsEscaped); appendSource(sb, end, sourceLength, false, sourceIsEscaped);
} }
@ -160,10 +115,12 @@ public class HtmlBuilder {
} }
public boolean hasLink(final int start, final int end) { public boolean hasLink(final int start, final int end) {
for (final LinkSpec spec : links) { for (final SpanSpec spec : spanSpecs) {
if (start >= spec.start && start <= spec.end || end >= spec.start && end <= spec.end) final int specStart = spec.getStart(), specEnd = spec.getEnd();
if (start >= specStart && start <= specEnd || end >= specStart && end <= specEnd) {
return true; return true;
} }
}
return false; return false;
} }
@ -175,7 +132,7 @@ public class HtmlBuilder {
", throwExceptions=" + throwExceptions + ", throwExceptions=" + throwExceptions +
", sourceIsEscaped=" + sourceIsEscaped + ", sourceIsEscaped=" + sourceIsEscaped +
", shouldReEscape=" + shouldReEscape + ", shouldReEscape=" + shouldReEscape +
", links=" + links + ", links=" + spanSpecs +
'}'; '}';
} }
@ -189,7 +146,7 @@ public class HtmlBuilder {
} }
} }
private void append(final StringBuilder builder, final String text, boolean escapeText, boolean textEscaped) { private static void append(final StringBuilder builder, final String text, boolean escapeText, boolean textEscaped) {
if (textEscaped == escapeText) { if (textEscaped == escapeText) {
builder.append(text); builder.append(text);
} else if (escapeText) { } else if (escapeText) {
@ -205,52 +162,101 @@ public class HtmlBuilder {
return shouldReEscape ? escape(source) : unescape(source); return shouldReEscape ? escape(source) : unescape(source);
} }
static final class LinkSpec implements Comparable<LinkSpec> { static abstract class SpanSpec implements Comparable<SpanSpec> {
final String link, display;
final int start, end; final int start, end;
final boolean displayIsHtml;
LinkSpec(final String link, final String display, final int start, final int end, final boolean displayIsHtml) { public final int getStart() {
this.link = link; return start;
this.display = display; }
public final int getEnd() {
return end;
}
public SpanSpec(int start, int end) {
this.start = start; this.start = start;
this.end = end; this.end = end;
this.displayIsHtml = displayIsHtml;
} }
@Override @Override
public int compareTo(@NonNull final LinkSpec that) { public int compareTo(@NonNull final SpanSpec that) {
return start - that.start; return start - that.start;
} }
@Override @Override
public boolean equals(final Object obj) { public boolean equals(Object o) {
if (this == obj) return true; if (this == o) return true;
if (obj == null) return false; if (o == null || getClass() != o.getClass()) return false;
if (!(obj instanceof LinkSpec)) return false;
final LinkSpec other = (LinkSpec) obj; SpanSpec spanSpec = (SpanSpec) o;
if (display == null) {
if (other.display != null) return false; if (start != spanSpec.start) return false;
} else if (!display.equals(other.display)) return false; return end == spanSpec.end;
if (displayIsHtml != other.displayIsHtml) return false;
if (end != other.end) return false;
if (link == null) {
if (other.link != null) return false;
} else if (!link.equals(other.link)) return false;
if (start != other.start) return false;
return true;
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; int result = start;
int result = 1; result = 31 * result + end;
result = prime * result + (display == null ? 0 : display.hashCode()); return result;
result = prime * result + (displayIsHtml ? 1231 : 1237); }
result = prime * result + end;
result = prime * result + (link == null ? 0 : link.hashCode()); @Override
result = prime * result + start; public String toString() {
return "SpanSpec{" +
"start=" + start +
", end=" + end +
'}';
}
public abstract void appendTo(StringBuilder sb);
}
static final class LinkSpec extends SpanSpec {
final String link, display;
final boolean displayIsHtml;
LinkSpec(final String link, final String display, final int start, final int end, final boolean displayIsHtml) {
super(start, end);
this.link = link;
this.display = display;
this.displayIsHtml = displayIsHtml;
}
@Override
public void appendTo(StringBuilder sb) {
if (isEmpty(display)) {
append(sb, link, false, false);
} else {
append(sb, display, false, displayIsHtml);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
LinkSpec linkSpec = (LinkSpec) o;
if (displayIsHtml != linkSpec.displayIsHtml) return false;
if (link != null ? !link.equals(linkSpec.link) : linkSpec.link != null) return false;
return display != null ? display.equals(linkSpec.display) : linkSpec.display == null;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (link != null ? link.hashCode() : 0);
result = 31 * result + (display != null ? display.hashCode() : 0);
result = 31 * result + (displayIsHtml ? 1 : 0);
return result; return result;
} }
@ -259,10 +265,8 @@ public class HtmlBuilder {
return "LinkSpec{" + return "LinkSpec{" +
"link='" + link + '\'' + "link='" + link + '\'' +
", display='" + display + '\'' + ", display='" + display + '\'' +
", start=" + start +
", end=" + end +
", displayIsHtml=" + displayIsHtml + ", displayIsHtml=" + displayIsHtml +
'}'; "} " + super.toString();
} }
} }

View File

@ -250,10 +250,10 @@ public class InternalTwitterContentUtils {
} }
} }
} }
return HtmlEscapeHelper.toPlainText(builder.build()); return builder.buildWithIndices().first;
} }
public static String formatUserDescription(final User user) { public static Pair<String, SpanItem[]> formatUserDescription(final User user) {
if (user == null) return null; if (user == null) return null;
final String text = user.getDescription(); final String text = user.getDescription();
if (text == null) return null; if (text == null) return null;
@ -267,7 +267,7 @@ public class InternalTwitterContentUtils {
} }
} }
} }
return builder.build(); return builder.buildWithIndices();
} }
public static String unescapeTwitterStatusText(final CharSequence text) { public static String unescapeTwitterStatusText(final CharSequence text) {
@ -275,14 +275,14 @@ public class InternalTwitterContentUtils {
return UNESCAPE_TWITTER_RAW_TEXT.translate(text); return UNESCAPE_TWITTER_RAW_TEXT.translate(text);
} }
public static String formatDirectMessageText(final DirectMessage message) { public static Pair<String, SpanItem[]> formatDirectMessageText(final DirectMessage message) {
if (message == null) return null; if (message == null) return null;
final HtmlBuilder builder = new HtmlBuilder(message.getText(), false, true, true); final HtmlBuilder builder = new HtmlBuilder(message.getText(), false, true, true);
parseEntities(builder, message, null); parseEntities(builder, message, null);
return builder.build(); return builder.buildWithIndices();
} }
public static Pair<String, List<SpanItem>> formatStatusTextWithIndices(final Status status) { public static Pair<String, SpanItem[]> formatStatusTextWithIndices(final Status status) {
if (status == null) return null; if (status == null) return null;
//TODO handle twitter video url //TODO handle twitter video url

View File

@ -222,7 +222,7 @@ public class TwidereQueryBuilder {
new Column(ConversationEntries.NAME), new Column(ConversationEntries.NAME),
new Column(ConversationEntries.SCREEN_NAME), new Column(ConversationEntries.SCREEN_NAME),
new Column(ConversationEntries.PROFILE_IMAGE_URL), new Column(ConversationEntries.PROFILE_IMAGE_URL),
new Column(ConversationEntries.TEXT_HTML), new Column(ConversationEntries.TEXT_UNESCAPED),
new Column(ConversationEntries.CONVERSATION_ID))); new Column(ConversationEntries.CONVERSATION_ID)));
final SQLSelectQuery.Builder entryIds = new SQLSelectQuery.Builder(); final SQLSelectQuery.Builder entryIds = new SQLSelectQuery.Builder();
entryIds.select(new Columns(new Column(DirectMessages._ID), entryIds.select(new Columns(new Column(DirectMessages._ID),
@ -233,7 +233,7 @@ public class TwidereQueryBuilder {
new Column(DirectMessages.SENDER_NAME, ConversationEntries.NAME), new Column(DirectMessages.SENDER_NAME, ConversationEntries.NAME),
new Column(DirectMessages.SENDER_SCREEN_NAME, ConversationEntries.SCREEN_NAME), new Column(DirectMessages.SENDER_SCREEN_NAME, ConversationEntries.SCREEN_NAME),
new Column(DirectMessages.SENDER_PROFILE_IMAGE_URL, ConversationEntries.PROFILE_IMAGE_URL), new Column(DirectMessages.SENDER_PROFILE_IMAGE_URL, ConversationEntries.PROFILE_IMAGE_URL),
new Column(DirectMessages.TEXT_HTML), new Column(DirectMessages.TEXT_UNESCAPED),
new Column(DirectMessages.SENDER_ID, ConversationEntries.CONVERSATION_ID))); new Column(DirectMessages.SENDER_ID, ConversationEntries.CONVERSATION_ID)));
entryIds.from(new Tables(Inbox.TABLE_NAME)); entryIds.from(new Tables(Inbox.TABLE_NAME));
entryIds.union(); entryIds.union();
@ -245,7 +245,7 @@ public class TwidereQueryBuilder {
new Column(DirectMessages.RECIPIENT_NAME, ConversationEntries.NAME), new Column(DirectMessages.RECIPIENT_NAME, ConversationEntries.NAME),
new Column(DirectMessages.RECIPIENT_SCREEN_NAME, ConversationEntries.SCREEN_NAME), new Column(DirectMessages.RECIPIENT_SCREEN_NAME, ConversationEntries.SCREEN_NAME),
new Column(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL, ConversationEntries.PROFILE_IMAGE_URL), new Column(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL, ConversationEntries.PROFILE_IMAGE_URL),
new Column(DirectMessages.TEXT_HTML), new Column(DirectMessages.TEXT_UNESCAPED),
new Column(DirectMessages.RECIPIENT_ID, ConversationEntries.CONVERSATION_ID))); new Column(DirectMessages.RECIPIENT_ID, ConversationEntries.CONVERSATION_ID)));
entryIds.from(new Tables(Outbox.TABLE_NAME)); entryIds.from(new Tables(Outbox.TABLE_NAME));
qb.from(entryIds.build()); qb.from(entryIds.build());

View File

@ -122,6 +122,9 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
} }
private void createViews(SQLiteDatabase db) { private void createViews(SQLiteDatabase db) {
db.execSQL(SQLQueryBuilder.dropView(true, DirectMessages.TABLE_NAME).getSQL());
db.execSQL(SQLQueryBuilder.dropView(true, DirectMessages.ConversationEntries.TABLE_NAME).getSQL());
db.execSQL(SQLQueryBuilder.createView(true, DirectMessages.TABLE_NAME) db.execSQL(SQLQueryBuilder.createView(true, DirectMessages.TABLE_NAME)
.as(DirectMessagesQueryBuilder.build()).buildSQL()); .as(DirectMessagesQueryBuilder.build()).buildSQL());
db.execSQL(SQLQueryBuilder.createView(true, DirectMessages.ConversationEntries.TABLE_NAME) db.execSQL(SQLQueryBuilder.createView(true, DirectMessages.ConversationEntries.TABLE_NAME)

View File

@ -81,7 +81,7 @@ public class MessageEntryViewHolder extends ViewHolder implements OnClickListene
nameView.setName(manager.getUserNickname(conversationId, name)); nameView.setName(manager.getUserNickname(conversationId, name));
nameView.setScreenName("@" + screenName); nameView.setScreenName("@" + screenName);
nameView.updateText(adapter.getBidiFormatter()); nameView.updateText(adapter.getBidiFormatter());
textView.setText(toPlainText(cursor.getString(ConversationEntries.IDX_TEXT))); textView.setText(toPlainText(cursor.getString(ConversationEntries.IDX_TEXT_UNESCAPED)));
timeView.setTime(timestamp); timeView.setTime(timestamp);
if (isOutgoing) { if (isOutgoing) {
timeView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_indicator_sent, 0); timeView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_indicator_sent, 0);

View File

@ -24,7 +24,7 @@ import android.content.res.ColorStateList;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.database.Cursor; import android.database.Cursor;
import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.Spannable; import android.text.SpannableStringBuilder;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
@ -33,8 +33,9 @@ import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.MessageConversationAdapter; import org.mariotaku.twidere.adapter.MessageConversationAdapter;
import org.mariotaku.twidere.model.ParcelableDirectMessageCursorIndices; import org.mariotaku.twidere.model.ParcelableDirectMessageCursorIndices;
import org.mariotaku.twidere.model.ParcelableMedia; import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.SpanItem;
import org.mariotaku.twidere.model.UserKey; import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.util.HtmlSpanBuilder; import org.mariotaku.twidere.model.util.ParcelableStatusUtils;
import org.mariotaku.twidere.util.JsonSerializer; import org.mariotaku.twidere.util.JsonSerializer;
import org.mariotaku.twidere.util.MediaLoaderWrapper; import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.ThemeUtils; import org.mariotaku.twidere.util.ThemeUtils;
@ -93,7 +94,10 @@ public class MessageViewHolder extends ViewHolder {
final long timestamp = cursor.getLong(indices.timestamp); final long timestamp = cursor.getLong(indices.timestamp);
final ParcelableMedia[] media = JsonSerializer.parseArray(cursor.getString(indices.media), final ParcelableMedia[] media = JsonSerializer.parseArray(cursor.getString(indices.media),
ParcelableMedia.class); ParcelableMedia.class);
final Spannable text = HtmlSpanBuilder.fromHtml(cursor.getString(indices.text_html)); final SpanItem[] spans = JsonSerializer.parseArray(cursor.getString(indices.spans),
SpanItem.class);
final SpannableStringBuilder text = SpannableStringBuilder.valueOf(cursor.getString(indices.text_unescaped));
ParcelableStatusUtils.applySpans(text, spans);
// Detect entity support // Detect entity support
linkify.applyAllLinks(text, accountKey, false, true); linkify.applyAllLinks(text, accountKey, false, true);
textView.setText(text); textView.setText(text);