fixed duplicate retweets icon
This commit is contained in:
parent
e4a618ff42
commit
62d4740e21
|
@ -35,7 +35,7 @@ subprojects {
|
|||
ObjectCursor : '0.9.20',
|
||||
PlayServices : '10.2.4',
|
||||
MapsUtils : '0.4.4',
|
||||
Crashlyrics : '2.6.7',
|
||||
Crashlyrics : '2.6.8',
|
||||
FabricPlugin : '1.22.1',
|
||||
PlayPublisher : '1.1.5',
|
||||
DropboxCoreSdk : '2.1.2',
|
||||
|
|
|
@ -9,23 +9,17 @@ import android.text.TextUtils;
|
|||
import org.apache.commons.lang3.text.translate.CharSequenceTranslator;
|
||||
import org.apache.commons.lang3.text.translate.EntityArrays;
|
||||
import org.apache.commons.lang3.text.translate.LookupTranslator;
|
||||
import org.mariotaku.commons.text.CodePointArray;
|
||||
import org.mariotaku.microblog.library.twitter.model.DMResponse;
|
||||
import org.mariotaku.microblog.library.twitter.model.DirectMessage;
|
||||
import org.mariotaku.microblog.library.twitter.model.EntitySupport;
|
||||
import org.mariotaku.microblog.library.twitter.model.ExtendedEntitySupport;
|
||||
import org.mariotaku.microblog.library.twitter.model.MediaEntity;
|
||||
import org.mariotaku.microblog.library.twitter.model.Status;
|
||||
import org.mariotaku.microblog.library.twitter.model.UrlEntity;
|
||||
import org.mariotaku.microblog.library.twitter.model.User;
|
||||
import org.mariotaku.twidere.extension.model.api.StatusExtensionsKt;
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
import org.mariotaku.twidere.model.SpanItem;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.util.database.FilterQueryBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import kotlin.Pair;
|
||||
|
||||
/**
|
||||
|
@ -130,124 +124,26 @@ public class InternalTwitterContentUtils {
|
|||
@NonNull
|
||||
public static Pair<String, SpanItem[]> formatDirectMessageText(@NonNull final DirectMessage message) {
|
||||
final HtmlBuilder builder = new HtmlBuilder(message.getText(), false, true, false);
|
||||
parseEntities(builder, message);
|
||||
StatusExtensionsKt.addEntities(builder, message);
|
||||
return builder.buildWithIndices();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Pair<String, SpanItem[]> formatDirectMessageText(@NonNull final DMResponse.Entry.Message.Data message) {
|
||||
final HtmlBuilder builder = new HtmlBuilder(message.getText(), false, true, false);
|
||||
parseEntities(builder, message);
|
||||
StatusExtensionsKt.addEntities(builder, message);
|
||||
return builder.buildWithIndices();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static StatusTextWithIndices formatStatusTextWithIndices(@NonNull final Status status) {
|
||||
//TODO handle twitter video url
|
||||
|
||||
String text = status.getFullText();
|
||||
CodePointArray source;
|
||||
// Display text range
|
||||
int[] range = null;
|
||||
if (text == null) {
|
||||
text = status.getText();
|
||||
source = new CodePointArray(text);
|
||||
} else {
|
||||
range = status.getDisplayTextRange();
|
||||
source = new CodePointArray(text);
|
||||
}
|
||||
final HtmlBuilder builder = new HtmlBuilder(source, false, true, false);
|
||||
parseEntities(builder, status);
|
||||
StatusTextWithIndices textWithIndices = new StatusTextWithIndices();
|
||||
final Pair<String, SpanItem[]> pair = builder.buildWithIndices();
|
||||
textWithIndices.text = pair.getFirst();
|
||||
textWithIndices.spans = pair.getSecond();
|
||||
if (range != null && range.length == 2) {
|
||||
textWithIndices.range = new int[2];
|
||||
textWithIndices.range[0] = getResultRangeLength(source, pair.getSecond(), 0, range[0]);
|
||||
textWithIndices.range[1] = pair.getFirst().length() - getResultRangeLength(source,
|
||||
pair.getSecond(), range[1], source.length());
|
||||
}
|
||||
return textWithIndices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param spans Ordered spans
|
||||
* @param start orig_start
|
||||
* @param end orig_end
|
||||
*/
|
||||
@NonNull
|
||||
static List<SpanItem> findByOrigRange(SpanItem[] spans, int start, int end) {
|
||||
List<SpanItem> result = new ArrayList<>();
|
||||
for (SpanItem span : spans) {
|
||||
if (span.orig_start >= start && span.orig_end <= end) {
|
||||
result.add(span);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int getResultRangeLength(CodePointArray source, SpanItem[] spans, int origStart, int origEnd) {
|
||||
List<SpanItem> findResult = findByOrigRange(spans, origStart, origEnd);
|
||||
if (findResult.isEmpty()) {
|
||||
return source.charCount(origStart, origEnd);
|
||||
}
|
||||
SpanItem first = findResult.get(0), last = findResult.get(findResult.size() - 1);
|
||||
if (first.orig_start == -1 || last.orig_end == -1)
|
||||
return source.charCount(origStart, origEnd);
|
||||
return source.charCount(origStart, first.orig_start) + (last.end - first.start)
|
||||
+ source.charCount(first.orig_end, origEnd);
|
||||
}
|
||||
|
||||
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) {
|
||||
// Format media.
|
||||
MediaEntity[] mediaEntities = null;
|
||||
if (entities instanceof ExtendedEntitySupport) {
|
||||
mediaEntities = ((ExtendedEntitySupport) entities).getExtendedMediaEntities();
|
||||
}
|
||||
if (mediaEntities == null) {
|
||||
mediaEntities = entities.getMediaEntities();
|
||||
}
|
||||
int[] startEnd = new int[2];
|
||||
if (mediaEntities != null) {
|
||||
for (final MediaEntity mediaEntity : mediaEntities) {
|
||||
final String mediaUrl = getMediaUrl(mediaEntity);
|
||||
if (mediaUrl != null && getStartEndForEntity(mediaEntity, startEnd)) {
|
||||
builder.addLink(mediaEntity.getExpandedUrl(), mediaEntity.getDisplayUrl(),
|
||||
startEnd[0], startEnd[1], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
final UrlEntity[] urlEntities = entities.getUrlEntities();
|
||||
if (urlEntities != null) {
|
||||
for (final UrlEntity urlEntity : urlEntities) {
|
||||
final String expandedUrl = urlEntity.getExpandedUrl();
|
||||
if (expandedUrl != null && getStartEndForEntity(urlEntity, startEnd)) {
|
||||
builder.addLink(expandedUrl, urlEntity.getDisplayUrl(), startEnd[0],
|
||||
startEnd[1], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean getStartEndForEntity(UrlEntity entity, @NonNull int[] out) {
|
||||
public static boolean getStartEndForEntity(UrlEntity entity, @NonNull int[] out) {
|
||||
out[0] = entity.getStart();
|
||||
out[1] = entity.getEnd();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String getOriginalId(@NonNull ParcelableStatus status) {
|
||||
return status.is_retweet ? status.retweet_id : status.id;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -189,6 +189,7 @@ public final class TwidereLinkify implements Constants {
|
|||
}
|
||||
string.removeSpan(span);
|
||||
String url = span.getURL();
|
||||
if (url == null) break;
|
||||
int linkType = type;
|
||||
if (span instanceof AcctMentionSpan) {
|
||||
linkType = LINK_TYPE_USER_ACCT;
|
||||
|
|
|
@ -3,9 +3,10 @@ package org.mariotaku.twidere.extension.model
|
|||
import org.mariotaku.ktextension.addAllTo
|
||||
import org.mariotaku.twidere.model.*
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/1/7.
|
||||
*/
|
||||
|
||||
val ParcelableStatus.originalId: String
|
||||
get() = if (is_retweet) retweet_id else id
|
||||
|
||||
val ParcelableStatus.media_type: Int
|
||||
get() = media?.firstOrNull()?.type ?: 0
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.extension.model.api
|
||||
|
||||
import org.mariotaku.microblog.library.twitter.model.EntitySupport
|
||||
import org.mariotaku.microblog.library.twitter.model.ExtendedEntitySupport
|
||||
import org.mariotaku.microblog.library.twitter.model.MediaEntity
|
||||
import org.mariotaku.microblog.library.twitter.model.UserMentionEntity
|
||||
import org.mariotaku.twidere.model.ParcelableMedia
|
||||
import org.mariotaku.twidere.model.ParcelableUserMention
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.util.ParcelableMediaUtils.getTypeInt
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils.getMediaUrl
|
||||
import org.mariotaku.twidere.util.media.preview.PreviewMediaExtractor.fromLink
|
||||
|
||||
fun UserMentionEntity.toParcelable(host: String?): ParcelableUserMention {
|
||||
val obj = ParcelableUserMention()
|
||||
obj.key = UserKey(id, host)
|
||||
obj.name = name
|
||||
obj.screen_name = screenName
|
||||
return obj
|
||||
}
|
||||
|
||||
fun EntitySupport.getEntityMedia(): Array<ParcelableMedia> {
|
||||
val list = ArrayList<ParcelableMedia>()
|
||||
val mediaEntities = if (this is ExtendedEntitySupport) {
|
||||
extendedMediaEntities ?: this.mediaEntities
|
||||
} else {
|
||||
this.mediaEntities
|
||||
}
|
||||
mediaEntities?.mapNotNullTo(list) { media ->
|
||||
return@mapNotNullTo media.toParcelable()
|
||||
}
|
||||
urlEntities?.mapNotNullTo(list) {
|
||||
fromLink(it.expandedUrl)
|
||||
}
|
||||
return list.toTypedArray()
|
||||
}
|
||||
|
||||
fun MediaEntity.toParcelable(): ParcelableMedia {
|
||||
val media = ParcelableMedia()
|
||||
val mediaUrl = getMediaUrl(this)
|
||||
media.url = mediaUrl
|
||||
media.media_url = mediaUrl
|
||||
media.preview_url = mediaUrl
|
||||
media.page_url = expandedUrl
|
||||
media.type = getTypeInt(type)
|
||||
media.alt_text = altText
|
||||
val size = sizes[MediaEntity.ScaleType.LARGE]
|
||||
if (size != null) {
|
||||
media.width = size.width
|
||||
media.height = size.height
|
||||
} else {
|
||||
media.width = 0
|
||||
media.height = 0
|
||||
}
|
||||
media.video_info = ParcelableMedia.VideoInfo.fromMediaEntityInfo(videoInfo)
|
||||
return media
|
||||
}
|
|
@ -21,7 +21,13 @@ package org.mariotaku.twidere.extension.model.api
|
|||
|
||||
import android.text.Spanned
|
||||
import android.text.style.URLSpan
|
||||
import org.apache.commons.lang3.text.translate.EntityArrays
|
||||
import org.apache.commons.lang3.text.translate.LookupTranslator
|
||||
import org.mariotaku.commons.text.CodePointArray
|
||||
import org.mariotaku.ktextension.mapToArray
|
||||
import org.mariotaku.microblog.library.twitter.model.EntitySupport
|
||||
import org.mariotaku.microblog.library.twitter.model.ExtendedEntitySupport
|
||||
import org.mariotaku.microblog.library.twitter.model.MediaEntity
|
||||
import org.mariotaku.microblog.library.twitter.model.Status
|
||||
import org.mariotaku.twidere.extension.model.toParcelable
|
||||
import org.mariotaku.twidere.extension.toSpanItem
|
||||
|
@ -30,8 +36,10 @@ import org.mariotaku.twidere.model.util.ParcelableLocationUtils
|
|||
import org.mariotaku.twidere.model.util.ParcelableMediaUtils
|
||||
import org.mariotaku.twidere.model.util.ParcelableStatusUtils.addFilterFlag
|
||||
import org.mariotaku.twidere.text.AcctMentionSpan
|
||||
import org.mariotaku.twidere.util.HtmlBuilder
|
||||
import org.mariotaku.twidere.util.HtmlSpanBuilder
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils.getMediaUrl
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils.getStartEndForEntity
|
||||
|
||||
fun Status.toParcelable(details: AccountDetails, profileImageSize: String = "normal"): ParcelableStatus {
|
||||
return toParcelable(details.key, details.type, profileImageSize).apply {
|
||||
|
@ -107,8 +115,8 @@ fun Status.applyTo(accountKey: UserKey, accountType: String, profileImageSize: S
|
|||
result.quoted_text_plain = result.quoted_text_unescaped
|
||||
result.quoted_spans = html?.spanItems
|
||||
} else {
|
||||
val textWithIndices = InternalTwitterContentUtils.formatStatusTextWithIndices(quoted)
|
||||
result.quoted_text_plain = InternalTwitterContentUtils.unescapeTwitterStatusText(quotedText)
|
||||
val textWithIndices = quoted.formattedTextWithIndices()
|
||||
result.quoted_text_plain = quotedText.twitterUnescaped()
|
||||
result.quoted_text_unescaped = textWithIndices.text
|
||||
result.quoted_spans = textWithIndices.spans
|
||||
extras.quoted_display_text_range = textWithIndices.range
|
||||
|
@ -160,9 +168,9 @@ fun Status.applyTo(accountKey: UserKey, accountType: String, profileImageSize: S
|
|||
result.text_plain = result.text_unescaped
|
||||
result.spans = html?.spanItems
|
||||
} else {
|
||||
val textWithIndices = InternalTwitterContentUtils.formatStatusTextWithIndices(status)
|
||||
val textWithIndices = status.formattedTextWithIndices()
|
||||
result.text_unescaped = textWithIndices.text
|
||||
result.text_plain = InternalTwitterContentUtils.unescapeTwitterStatusText(text)
|
||||
result.text_plain = text.twitterUnescaped()
|
||||
result.spans = textWithIndices.spans
|
||||
extras.display_text_range = textWithIndices.range
|
||||
}
|
||||
|
@ -185,6 +193,82 @@ fun Status.applyTo(accountKey: UserKey, accountType: String, profileImageSize: S
|
|||
result.extras = extras
|
||||
}
|
||||
|
||||
|
||||
fun Status.formattedTextWithIndices(): StatusTextWithIndices {
|
||||
val source = CodePointArray(this.fullText ?: this.text!!)
|
||||
val builder = HtmlBuilder(source, false, true, false)
|
||||
builder.addEntities(this)
|
||||
val textWithIndices = StatusTextWithIndices()
|
||||
val (text, spans) = builder.buildWithIndices()
|
||||
textWithIndices.text = text
|
||||
textWithIndices.spans = spans
|
||||
|
||||
// Display text range
|
||||
val range = displayTextRange?.takeIf { it.size == 2 }
|
||||
if (range != null) {
|
||||
textWithIndices.range = intArrayOf(
|
||||
source.findResultRangeLength(spans, 0, range[0]),
|
||||
text.length - source.findResultRangeLength(spans, range[1], source.length())
|
||||
)
|
||||
}
|
||||
return textWithIndices
|
||||
}
|
||||
|
||||
|
||||
fun CodePointArray.findResultRangeLength(spans: Array<SpanItem>, origStart: Int, origEnd: Int): Int {
|
||||
val findResult = findByOrigRange(spans, origStart, origEnd)
|
||||
if (findResult.isEmpty()) {
|
||||
return charCount(origStart, origEnd)
|
||||
}
|
||||
val first = findResult.first()
|
||||
val last = findResult.last()
|
||||
if (first.orig_start == -1 || last.orig_end == -1)
|
||||
return charCount(origStart, origEnd)
|
||||
return charCount(origStart, first.orig_start) + (last.end - first.start) + charCount(first.orig_end, origEnd)
|
||||
}
|
||||
|
||||
|
||||
fun HtmlBuilder.addEntities(entities: EntitySupport) {
|
||||
// Format media.
|
||||
var mediaEntities: Array<MediaEntity>? = null
|
||||
if (entities is ExtendedEntitySupport) {
|
||||
mediaEntities = entities.extendedMediaEntities
|
||||
}
|
||||
if (mediaEntities == null) {
|
||||
mediaEntities = entities.mediaEntities
|
||||
}
|
||||
val startEnd = IntArray(2)
|
||||
mediaEntities?.forEach { mediaEntity ->
|
||||
val mediaUrl = getMediaUrl(mediaEntity)
|
||||
if (mediaUrl != null && getStartEndForEntity(mediaEntity, startEnd)) {
|
||||
addLink(mediaEntity.expandedUrl, mediaEntity.displayUrl,
|
||||
startEnd[0], startEnd[1], false)
|
||||
}
|
||||
}
|
||||
entities.urlEntities?.forEach { urlEntity ->
|
||||
val expandedUrl = urlEntity.expandedUrl
|
||||
if (expandedUrl != null && getStartEndForEntity(urlEntity, startEnd)) {
|
||||
addLink(expandedUrl, urlEntity.displayUrl, startEnd[0],
|
||||
startEnd[1], false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.twitterUnescaped(): String {
|
||||
return twitterRawTextTranslator.translate(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param spans Ordered spans
|
||||
* *
|
||||
* @param start orig_start
|
||||
* *
|
||||
* @param end orig_end
|
||||
*/
|
||||
internal fun findByOrigRange(spans: Array<SpanItem>, start: Int, end: Int): List<SpanItem> {
|
||||
return spans.filter { it.orig_start >= start && it.orig_end <= end }
|
||||
}
|
||||
|
||||
internal inline val CharSequence.spanItems get() = (this as? Spanned)?.let { text ->
|
||||
text.getSpans(0, length, URLSpan::class.java).mapToArray {
|
||||
val item = it.toSpanItem(text)
|
||||
|
@ -246,4 +330,12 @@ private fun Status.getInReplyToUserKey(accountKey: UserKey): UserKey? {
|
|||
return UserKey(inReplyToUserId, accountKey.host)
|
||||
}
|
||||
|
||||
private val noticeUriRegex = Regex("tag:([\\w\\d.]+),(\\d{4}-\\d{2}-\\d{2}):noticeId=(\\d+):objectType=(\\w+)")
|
||||
private val noticeUriRegex = Regex("tag:([\\w\\d.]+),(\\d{4}-\\d{2}-\\d{2}):noticeId=(\\d+):objectType=(\\w+)")
|
||||
|
||||
private object twitterRawTextTranslator : LookupTranslator(*EntityArrays.BASIC_UNESCAPE())
|
||||
|
||||
class StatusTextWithIndices {
|
||||
var text: String? = null
|
||||
var spans: Array<SpanItem>? = null
|
||||
var range: IntArray? = null
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.extension.model.api
|
||||
|
||||
import org.mariotaku.microblog.library.twitter.model.UserMentionEntity
|
||||
import org.mariotaku.twidere.model.ParcelableUserMention
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
|
||||
fun UserMentionEntity.toParcelable(host: String?): ParcelableUserMention {
|
||||
val obj = ParcelableUserMention()
|
||||
obj.key = UserKey(id, host)
|
||||
obj.name = name
|
||||
obj.screen_name = screenName
|
||||
return obj
|
||||
}
|
|
@ -25,7 +25,7 @@ import org.mariotaku.twidere.model.ParcelableMedia
|
|||
/**
|
||||
* Created by mariotaku on 2017/4/30.
|
||||
*/
|
||||
fun Attachment.toParcelable(externalUrl: String) : ParcelableMedia? {
|
||||
fun Attachment.toParcelable(externalUrl: String?) : ParcelableMedia? {
|
||||
val mimeType = mimetype ?: return null
|
||||
val result = ParcelableMedia()
|
||||
|
||||
|
|
|
@ -1445,7 +1445,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
internal set
|
||||
var translationResult: TranslationResult? = null
|
||||
internal set(translation) {
|
||||
if (status == null || translation == null || !TextUtils.equals(InternalTwitterContentUtils.getOriginalId(status!!), translation.id)) {
|
||||
if (translation == null || status?.originalId != translation.id) {
|
||||
field = null
|
||||
} else {
|
||||
field = translation
|
||||
|
@ -2070,6 +2070,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
try {
|
||||
activitySummary.retweeters = twitter.getRetweets(statusId, paging)
|
||||
.filterNot { DataStoreUtils.isFilteringUser(context, it.user.key) }
|
||||
.distinctBy { it.user.id }
|
||||
.map { it.user.toParcelable(details) }
|
||||
val countValues = ContentValues()
|
||||
val status = twitter.showStatus(statusId)
|
||||
|
@ -2120,7 +2121,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
) {
|
||||
|
||||
fun isStatus(status: ParcelableStatus): Boolean {
|
||||
return TextUtils.equals(statusId, if (status.is_retweet) status.retweet_id else status.id)
|
||||
return statusId == status.retweet_id ?: status.id
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,6 @@ import org.mariotaku.microblog.library.mastodon.Mastodon
|
|||
import org.mariotaku.microblog.library.twitter.model.FriendshipUpdate
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging
|
||||
import org.mariotaku.microblog.library.twitter.model.UserList
|
||||
import org.mariotaku.twidere.BuildConfig
|
||||
import org.mariotaku.twidere.Constants.*
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.activity.AccountSelectorActivity
|
||||
|
@ -786,7 +785,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
|
|||
mentionItem.title = getString(R.string.mention_user_name, displayName)
|
||||
}
|
||||
menu.setItemAvailability(R.id.mention, !isMyself)
|
||||
menu.setItemAvailability(R.id.qr_code, isMyself || BuildConfig.DEBUG)
|
||||
menu.setItemAvailability(R.id.incoming_friendships, isMyself)
|
||||
menu.setItemAvailability(R.id.saved_searches, isMyself)
|
||||
|
||||
|
|
|
@ -3,73 +3,25 @@ package org.mariotaku.twidere.model.util
|
|||
import org.mariotaku.ktextension.addAllTo
|
||||
import org.mariotaku.ktextension.isNullOrEmpty
|
||||
import org.mariotaku.ktextension.toIntOr
|
||||
import org.mariotaku.microblog.library.twitter.model.*
|
||||
import org.mariotaku.microblog.library.twitter.model.CardEntity
|
||||
import org.mariotaku.microblog.library.twitter.model.MediaEntity
|
||||
import org.mariotaku.microblog.library.twitter.model.Status
|
||||
import org.mariotaku.microblog.library.twitter.model.UrlEntity
|
||||
import org.mariotaku.twidere.extension.model.api.getEntityMedia
|
||||
import org.mariotaku.twidere.extension.model.api.gnusocial.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.toParcelable
|
||||
import org.mariotaku.twidere.model.ParcelableMedia
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import org.mariotaku.twidere.util.media.preview.PreviewMediaExtractor
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/2/13.
|
||||
*/
|
||||
object ParcelableMediaUtils {
|
||||
|
||||
fun fromEntities(entities: EntitySupport): Array<ParcelableMedia> {
|
||||
val list = ArrayList<ParcelableMedia>()
|
||||
val mediaEntities: Array<MediaEntity>?
|
||||
if (entities is ExtendedEntitySupport) {
|
||||
val extendedMediaEntities = entities.extendedMediaEntities
|
||||
mediaEntities = extendedMediaEntities ?: entities.mediaEntities
|
||||
} else {
|
||||
mediaEntities = entities.mediaEntities
|
||||
}
|
||||
if (mediaEntities != null) {
|
||||
for (media in mediaEntities) {
|
||||
val mediaURL = InternalTwitterContentUtils.getMediaUrl(media)
|
||||
if (mediaURL != null) {
|
||||
list.add(ParcelableMediaUtils.fromMediaEntity(media))
|
||||
}
|
||||
}
|
||||
}
|
||||
val urlEntities = entities.urlEntities
|
||||
if (urlEntities != null) {
|
||||
for (url in urlEntities) {
|
||||
val expanded = url.expandedUrl
|
||||
val media = PreviewMediaExtractor.fromLink(expanded)
|
||||
if (media != null) {
|
||||
list.add(media)
|
||||
}
|
||||
}
|
||||
}
|
||||
return list.toTypedArray()
|
||||
}
|
||||
|
||||
fun fromMediaEntity(entity: MediaEntity): ParcelableMedia {
|
||||
val media = ParcelableMedia()
|
||||
val mediaUrl = InternalTwitterContentUtils.getMediaUrl(entity)
|
||||
media.url = mediaUrl
|
||||
media.media_url = mediaUrl
|
||||
media.preview_url = mediaUrl
|
||||
media.page_url = entity.expandedUrl
|
||||
media.type = ParcelableMediaUtils.getTypeInt(entity.type)
|
||||
media.alt_text = entity.altText
|
||||
val size = entity.sizes[MediaEntity.ScaleType.LARGE]
|
||||
if (size != null) {
|
||||
media.width = size.width
|
||||
media.height = size.height
|
||||
} else {
|
||||
media.width = 0
|
||||
media.height = 0
|
||||
}
|
||||
media.video_info = ParcelableMedia.VideoInfo.fromMediaEntityInfo(entity.videoInfo)
|
||||
return media
|
||||
}
|
||||
|
||||
fun fromStatus(status: Status, accountKey: UserKey, accountType: String): Array<ParcelableMedia>? {
|
||||
return fromEntities(status) + fromAttachments(status) + fromCard(status.card,
|
||||
return status.getEntityMedia() + status.getAttachmentMedia() + fromCard(status.card,
|
||||
status.urlEntities, status.mediaEntities, status.extendedMediaEntities, accountKey,
|
||||
accountType) + fromPhoto(status)
|
||||
}
|
||||
|
@ -85,10 +37,10 @@ object ParcelableMediaUtils {
|
|||
return arrayOf(media)
|
||||
}
|
||||
|
||||
private fun fromAttachments(status: Status): Array<ParcelableMedia> {
|
||||
val attachments = status.attachments ?: return emptyArray()
|
||||
val externalUrl = status.externalUrl
|
||||
return attachments.mapNotNull { it.toParcelable(externalUrl) }.toTypedArray()
|
||||
private fun Status.getAttachmentMedia(): Array<ParcelableMedia> {
|
||||
return attachments?.mapNotNull {
|
||||
it.toParcelable(externalUrl)
|
||||
}?.toTypedArray() ?: emptyArray()
|
||||
}
|
||||
|
||||
private fun fromCard(card: CardEntity?, urlEntities: Array<UrlEntity>?,
|
||||
|
|
|
@ -6,6 +6,7 @@ import org.mariotaku.microblog.library.twitter.model.DMResponse.Entry.Message
|
|||
import org.mariotaku.microblog.library.twitter.model.DMResponse.Entry.Message.Data
|
||||
import org.mariotaku.microblog.library.twitter.model.DirectMessage
|
||||
import org.mariotaku.microblog.library.twitter.model.User
|
||||
import org.mariotaku.twidere.extension.model.api.getEntityMedia
|
||||
import org.mariotaku.twidere.extension.model.api.key
|
||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
import org.mariotaku.twidere.model.ParcelableMedia
|
||||
|
@ -169,7 +170,7 @@ object ParcelableMessageUtils {
|
|||
this.extras = extras
|
||||
this.text_unescaped = text
|
||||
this.spans = spans
|
||||
this.media = ParcelableMediaUtils.fromEntities(message)
|
||||
this.media = message.getEntityMedia()
|
||||
}
|
||||
|
||||
private fun typeAndExtras(message: DirectMessage): Pair<String, MessageExtras?> {
|
||||
|
@ -187,17 +188,17 @@ object ParcelableMessageUtils {
|
|||
when {
|
||||
attachment.photo != null -> {
|
||||
val photo = attachment.photo
|
||||
val media = arrayOf(ParcelableMediaUtils.fromMediaEntity(photo))
|
||||
val media = arrayOf(photo.toParcelable())
|
||||
return Triple(MessageType.TEXT, null, media)
|
||||
}
|
||||
attachment.video != null -> {
|
||||
val video = attachment.video
|
||||
val media = arrayOf(ParcelableMediaUtils.fromMediaEntity(video))
|
||||
val media = arrayOf(video.toParcelable())
|
||||
return Triple(MessageType.TEXT, null, media)
|
||||
}
|
||||
attachment.animatedGif != null -> {
|
||||
val video = attachment.animatedGif
|
||||
val media = arrayOf(ParcelableMediaUtils.fromMediaEntity(video))
|
||||
val media = arrayOf(video.toParcelable())
|
||||
return Triple(MessageType.TEXT, null, media)
|
||||
}
|
||||
attachment.sticker != null -> {
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package org.mariotaku.twidere.model.util
|
||||
|
||||
import org.mariotaku.microblog.library.twitter.model.UserMentionEntity
|
||||
import org.mariotaku.twidere.model.ParcelableUserMention
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
|
||||
fun UserMentionEntity.toParcelable(host: String?): ParcelableUserMention {
|
||||
val obj = ParcelableUserMention()
|
||||
obj.key = UserKey(id, host)
|
||||
obj.name = name
|
||||
obj.screen_name = screenName
|
||||
return obj
|
||||
}
|
|
@ -45,6 +45,7 @@ import org.mariotaku.twidere.annotation.NotificationType
|
|||
import org.mariotaku.twidere.constant.IntentConstants
|
||||
import org.mariotaku.twidere.constant.iWantMyStarsBackKey
|
||||
import org.mariotaku.twidere.constant.nameFirstKey
|
||||
import org.mariotaku.twidere.extension.model.api.formattedTextWithIndices
|
||||
import org.mariotaku.twidere.extension.model.getSummaryText
|
||||
import org.mariotaku.twidere.extension.model.getTitle
|
||||
import org.mariotaku.twidere.extension.model.notificationDisabled
|
||||
|
@ -340,10 +341,10 @@ class ContentNotificationManager(
|
|||
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
||||
if (status.isRetweetedByMe) {
|
||||
builder.setContentTitle(context.getString(R.string.notification_title_new_retweet_by_user, userDisplayName))
|
||||
builder.setContentText(InternalTwitterContentUtils.formatStatusTextWithIndices(status.retweetedStatus).text)
|
||||
builder.setContentText(status.retweetedStatus.formattedTextWithIndices().text)
|
||||
} else {
|
||||
builder.setContentTitle(context.getString(R.string.notification_title_new_status_by_user, userDisplayName))
|
||||
builder.setContentText(InternalTwitterContentUtils.formatStatusTextWithIndices(status).text)
|
||||
builder.setContentText(status.formattedTextWithIndices().text)
|
||||
}
|
||||
builder.setContentIntent(PendingIntent.getActivity(context, 0, Intent(Intent.ACTION_VIEW, statusUri).apply {
|
||||
setClass(context, LinkHandlerActivity::class.java)
|
||||
|
|
Loading…
Reference in New Issue