improved DM item - hides text when there's only media

This commit is contained in:
Mariotaku Lee 2017-02-11 16:04:11 +08:00
parent f665318eb6
commit d819fa9bd1
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
15 changed files with 254 additions and 136 deletions

View File

@ -23,6 +23,7 @@ package org.mariotaku.twidere.model;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.annotation.IntDef;
import android.text.Spanned; import android.text.Spanned;
import android.text.style.URLSpan; import android.text.style.URLSpan;
@ -67,6 +68,10 @@ public class SpanItem implements Parcelable {
@ParcelableNoThanks @ParcelableNoThanks
public int orig_end = -1; public int orig_end = -1;
@ParcelableNoThanks
@SpanType
public int type = SpanType.LINK;
@Override @Override
public String toString() { public String toString() {
return "SpanItem{" + return "SpanItem{" +
@ -95,4 +100,10 @@ public class SpanItem implements Parcelable {
spanItem.end = spanned.getSpanEnd(span); spanItem.end = spanned.getSpanEnd(span);
return spanItem; return spanItem;
} }
@IntDef({SpanType.HIDE, SpanType.LINK})
public @interface SpanType {
int HIDE = -1;
int LINK = 0;
}
} }

View File

@ -1,28 +0,0 @@
package org.mariotaku.twidere.text;
import android.text.SpannableStringBuilder;
import org.mariotaku.twidere.util.CheckUtils;
import org.mariotaku.twidere.util.TwidereStringUtils;
/**
* Created by Ningyuan on 2015/5/1.
*/
public class SafeSpannableStringBuilder extends SpannableStringBuilder {
public SafeSpannableStringBuilder(CharSequence source) {
super(source);
TwidereStringUtils.fixSHY(this);
}
@Override
public void setSpan(Object what, int start, int end, int flags) {
if (!CheckUtils.checkRange(this, start, end)) {
// Silently ignore
return;
}
super.setSpan(what, start, end, flags);
}
}

View File

@ -1,45 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 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.text;
import android.text.TextPaint;
import android.text.style.CharacterStyle;
import static org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT;
import static org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE;
public class TwidereHighLightStyle extends CharacterStyle {
private final int option;
public TwidereHighLightStyle(final int option) {
this.option = option;
}
@Override
public void updateDrawState(final TextPaint ds) {
if ((option & VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE) != 0) {
ds.setUnderlineText(true);
}
if ((option & VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT) != 0) {
ds.setColor(ds.linkColor);
}
}
}

View File

@ -19,12 +19,11 @@
package org.mariotaku.twidere.util; package org.mariotaku.twidere.util;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.Spannable; import android.text.Spannable;
import android.text.Spanned; import android.text.Spanned;
import android.text.style.ReplacementSpan;
import org.mariotaku.twidere.text.ZeroWidthSpan;
/** /**
* Created by mariotaku on 14/12/23. * Created by mariotaku on 14/12/23.
@ -61,16 +60,4 @@ public class TwidereStringUtils {
} }
} }
private static class ZeroWidthSpan extends ReplacementSpan {
@Override
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
return 0;
}
@Override
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
}
}
} }

View File

@ -24,11 +24,16 @@ import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import org.apache.commons.lang3.time.DateUtils import org.apache.commons.lang3.time.DateUtils
import org.mariotaku.kpreferences.get
import org.mariotaku.twidere.adapter.iface.IItemCountsAdapter import org.mariotaku.twidere.adapter.iface.IItemCountsAdapter
import org.mariotaku.twidere.annotation.PreviewStyle
import org.mariotaku.twidere.constant.linkHighlightOptionKey
import org.mariotaku.twidere.constant.mediaPreviewStyleKey
import org.mariotaku.twidere.extension.model.timestamp import org.mariotaku.twidere.extension.model.timestamp
import org.mariotaku.twidere.model.ItemCounts import org.mariotaku.twidere.model.ItemCounts
import org.mariotaku.twidere.model.ParcelableMessage import org.mariotaku.twidere.model.ParcelableMessage
import org.mariotaku.twidere.model.ParcelableMessage.MessageType import org.mariotaku.twidere.model.ParcelableMessage.MessageType
import org.mariotaku.twidere.util.TwidereLinkify
import org.mariotaku.twidere.view.holder.message.AbsMessageViewHolder import org.mariotaku.twidere.view.holder.message.AbsMessageViewHolder
import org.mariotaku.twidere.view.holder.message.MessageViewHolder import org.mariotaku.twidere.view.holder.message.MessageViewHolder
import org.mariotaku.twidere.view.holder.message.StickerMessageViewHolder import org.mariotaku.twidere.view.holder.message.StickerMessageViewHolder
@ -38,6 +43,12 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter<Rec
IItemCountsAdapter { IItemCountsAdapter {
private val calendars = Pair(Calendar.getInstance(), Calendar.getInstance()) private val calendars = Pair(Calendar.getInstance(), Calendar.getInstance())
override val itemCounts: ItemCounts = ItemCounts(1) override val itemCounts: ItemCounts = ItemCounts(1)
@PreviewStyle
val mediaPreviewStyle: Int = preferences[mediaPreviewStyleKey]
val linkHighlightingStyle: Int = preferences[linkHighlightOptionKey]
val linkify: TwidereLinkify = TwidereLinkify(null)
var messages: List<ParcelableMessage>? = null var messages: List<ParcelableMessage>? = null
set(value) { set(value) {
field = value field = value

View File

@ -0,0 +1,43 @@
/*
* 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
import android.text.Spannable
import android.text.Spanned
import android.text.style.URLSpan
import org.mariotaku.twidere.model.SpanItem
import org.mariotaku.twidere.text.ZeroWidthSpan
val SpanItem.length: Int get() = end - start
fun Array<SpanItem>.applyTo(spannable: Spannable) {
forEach { span ->
when (span.type) {
SpanItem.SpanType.HIDE -> {
spannable.setSpan(ZeroWidthSpan(), span.start, span.end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
else -> {
spannable.setSpan(URLSpan(span.link), span.start, span.end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
}
}

View File

@ -91,6 +91,7 @@ import org.mariotaku.twidere.annotation.Referral
import org.mariotaku.twidere.constant.* import org.mariotaku.twidere.constant.*
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.* import org.mariotaku.twidere.constant.KeyboardShortcutConstants.*
import org.mariotaku.twidere.extension.applyTheme import org.mariotaku.twidere.extension.applyTheme
import org.mariotaku.twidere.extension.model.applyTo
import org.mariotaku.twidere.extension.model.getAccountType import org.mariotaku.twidere.extension.model.getAccountType
import org.mariotaku.twidere.extension.model.media_type import org.mariotaku.twidere.extension.model.media_type
import org.mariotaku.twidere.loader.ConversationLoader import org.mariotaku.twidere.loader.ConversationLoader
@ -861,7 +862,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
} }
val quotedText = SpannableStringBuilder.valueOf(status.quoted_text_unescaped) val quotedText = SpannableStringBuilder.valueOf(status.quoted_text_unescaped)
ParcelableStatusUtils.applySpans(quotedText, status.quoted_spans) status.quoted_spans?.applyTo(quotedText)
linkify.applyAllLinks(quotedText, status.account_key, layoutPosition.toLong(), linkify.applyAllLinks(quotedText, status.account_key, layoutPosition.toLong(),
status.is_possibly_sensitive, skipLinksInText) status.is_possibly_sensitive, skipLinksInText)
if (quotedDisplayEnd != -1 && quotedDisplayEnd <= quotedText.length) { if (quotedDisplayEnd != -1 && quotedDisplayEnd <= quotedText.length) {
@ -962,10 +963,11 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
displayEnd = status.extras.display_text_range!![1] displayEnd = status.extras.display_text_range!![1]
} }
val text = SpannableStringBuilder.valueOf(status.text_unescaped) val text = SpannableStringBuilder.valueOf(status.text_unescaped).apply {
ParcelableStatusUtils.applySpans(text, status.spans) status.spans?.applyTo(this)
linkify.applyAllLinks(text, status.account_key, layoutPosition.toLong(), linkify.applyAllLinks(this, status.account_key, layoutPosition.toLong(),
status.is_possibly_sensitive, skipLinksInText) status.is_possibly_sensitive, skipLinksInText)
}
if (displayEnd != -1 && displayEnd <= text.length) { if (displayEnd != -1 && displayEnd <= text.length) {
itemView.text.text = text.subSequence(0, displayEnd) itemView.text.text = text.subSequence(0, displayEnd)
@ -1489,7 +1491,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
class StatusAdapter(val fragment: StatusFragment) : LoadMoreSupportAdapter<ViewHolder>(fragment.context), IStatusesAdapter<List<ParcelableStatus>> { class StatusAdapter(val fragment: StatusFragment) : LoadMoreSupportAdapter<ViewHolder>(fragment.context), IStatusesAdapter<List<ParcelableStatus>> {
private val inflater: LayoutInflater private val inflater: LayoutInflater
override val mediaLoadingHandler: MediaLoadingHandler override val mediaLoadingHandler = MediaLoadingHandler(R.id.media_preview_progress)
override val twidereLinkify: TwidereLinkify override val twidereLinkify: TwidereLinkify
override var statusClickListener: StatusClickListener? = null override var statusClickListener: StatusClickListener? = null
@ -1498,15 +1500,15 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
private val itemCounts = ItemCounts(ITEM_TYPES_SUM) private val itemCounts = ItemCounts(ITEM_TYPES_SUM)
override val nameFirst: Boolean
private val cardBackgroundColor: Int private val cardBackgroundColor: Int
override val mediaPreviewStyle: Int override val nameFirst = preferences[nameFirstKey]
override val linkHighlightingStyle: Int override val mediaPreviewStyle = preferences[mediaPreviewStyleKey]
override val lightFont: Boolean override val linkHighlightingStyle = preferences[linkHighlightOptionKey]
override val mediaPreviewEnabled: Boolean override val lightFont = preferences[lightFontKey]
override val sensitiveContentEnabled: Boolean override val mediaPreviewEnabled = preferences[mediaPreviewKey]
private val showCardActions: Boolean override val sensitiveContentEnabled = preferences[displaySensitiveContentsKey]
override val useStarsForLikes: Boolean private val showCardActions = !preferences[hideCardActionsKey]
override val useStarsForLikes = preferences[iWantMyStarsBackKey]
private var mDetailMediaExpanded: Boolean = false private var mDetailMediaExpanded: Boolean = false
var status: ParcelableStatus? = null var status: ParcelableStatus? = null
@ -1547,18 +1549,9 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
itemCounts[ITEM_IDX_CONVERSATION_LOAD_MORE] = 1 itemCounts[ITEM_IDX_CONVERSATION_LOAD_MORE] = 1
itemCounts[ITEM_IDX_REPLY_LOAD_MORE] = 1 itemCounts[ITEM_IDX_REPLY_LOAD_MORE] = 1
inflater = LayoutInflater.from(context) inflater = LayoutInflater.from(context)
mediaLoadingHandler = MediaLoadingHandler(R.id.media_preview_progress)
cardBackgroundColor = ThemeUtils.getCardBackgroundColor(context, cardBackgroundColor = ThemeUtils.getCardBackgroundColor(context,
ThemeUtils.getThemeBackgroundOption(context), ThemeUtils.getThemeBackgroundOption(context),
ThemeUtils.getUserThemeBackgroundAlpha(context)) ThemeUtils.getUserThemeBackgroundAlpha(context))
nameFirst = preferences[nameFirstKey]
lightFont = preferences[lightFontKey]
mediaPreviewStyle = preferences[mediaPreviewStyleKey]
linkHighlightingStyle = preferences[linkHighlightOptionKey]
mediaPreviewEnabled = preferences[mediaPreviewKey]
sensitiveContentEnabled = preferences.getBoolean(SharedPreferenceConstants.KEY_DISPLAY_SENSITIVE_CONTENTS, false)
showCardActions = !preferences[hideCardActionsKey]
useStarsForLikes = preferences[iWantMyStarsBackKey]
val listener = StatusAdapterLinkClickHandler<List<ParcelableStatus>>(context, preferences) val listener = StatusAdapterLinkClickHandler<List<ParcelableStatus>>(context, preferences)
listener.setAdapter(this) listener.setAdapter(this)
twidereLinkify = TwidereLinkify(listener) twidereLinkify = TwidereLinkify(listener)

View File

@ -105,6 +105,7 @@ import org.mariotaku.twidere.constant.lightFontKey
import org.mariotaku.twidere.constant.newDocumentApiKey import org.mariotaku.twidere.constant.newDocumentApiKey
import org.mariotaku.twidere.constant.profileImageStyleKey import org.mariotaku.twidere.constant.profileImageStyleKey
import org.mariotaku.twidere.extension.applyTheme import org.mariotaku.twidere.extension.applyTheme
import org.mariotaku.twidere.extension.model.applyTo
import org.mariotaku.twidere.fragment.AbsStatusesFragment.StatusesFragmentDelegate import org.mariotaku.twidere.fragment.AbsStatusesFragment.StatusesFragmentDelegate
import org.mariotaku.twidere.fragment.UserTimelineFragment.UserTimelineFragmentDelegate import org.mariotaku.twidere.fragment.UserTimelineFragment.UserTimelineFragmentDelegate
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback
@ -471,9 +472,10 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
profileNameContainer.screenName.text = "@${user.screen_name}" profileNameContainer.screenName.text = "@${user.screen_name}"
val linkify = TwidereLinkify(this) val linkify = TwidereLinkify(this)
if (user.description_unescaped != null) { if (user.description_unescaped != null) {
val text = SpannableStringBuilder.valueOf(user.description_unescaped) val text = SpannableStringBuilder.valueOf(user.description_unescaped).apply {
ParcelableStatusUtils.applySpans(text, user.description_spans) user.description_spans?.applyTo(this)
linkify.applyAllLinks(text, user.account_key, false, false) linkify.applyAllLinks(this, user.account_key, false, false)
}
descriptionContainer.description.text = text descriptionContainer.description.text = text
} else { } else {
descriptionContainer.description.text = user.description_plain descriptionContainer.description.text = user.description_plain

View File

@ -4,6 +4,7 @@ import android.text.Spannable
import android.text.Spanned import android.text.Spanned
import android.text.style.URLSpan import android.text.style.URLSpan
import org.mariotaku.microblog.library.twitter.model.Status import org.mariotaku.microblog.library.twitter.model.Status
import org.mariotaku.twidere.extension.model.applyTo
import org.mariotaku.twidere.model.* import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.ParcelableStatus.FilterFlags import org.mariotaku.twidere.model.ParcelableStatus.FilterFlags
import org.mariotaku.twidere.util.HtmlSpanBuilder import org.mariotaku.twidere.util.HtmlSpanBuilder
@ -254,13 +255,6 @@ object ParcelableStatusUtils {
return status.inReplyToScreenName return status.inReplyToScreenName
} }
fun applySpans(text: Spannable, spans: Array<SpanItem>?) {
spans?.forEach { span ->
text.setSpan(URLSpan(span.link), span.start, span.end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
fun updateExtraInformation(status: ParcelableStatus, details: AccountDetails) { fun updateExtraInformation(status: ParcelableStatus, details: AccountDetails) {
status.account_color = details.color status.account_color = details.color
} }

View File

@ -17,17 +17,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.mariotaku.twidere.text; package org.mariotaku.twidere.text
import android.text.TextPaint; import android.text.TextPaint
import android.text.style.CharacterStyle; import android.text.style.CharacterStyle
/** /**
* Created by mariotaku on 15/5/11. * Created by mariotaku on 15/5/11.
*/ */
public class MarkForDeleteSpan extends CharacterStyle { class MarkForDeleteSpan : CharacterStyle() {
@Override override fun updateDrawState(tp: TextPaint) {
public void updateDrawState(TextPaint tp) {
} }
} }

View File

@ -0,0 +1,26 @@
package org.mariotaku.twidere.text
import android.text.SpannableStringBuilder
import org.mariotaku.twidere.util.CheckUtils
import org.mariotaku.twidere.util.TwidereStringUtils
/**
* Created by Ningyuan on 2015/5/1.
*/
class SafeSpannableStringBuilder(source: CharSequence) : SpannableStringBuilder(source) {
init {
TwidereStringUtils.fixSHY(this)
}
override fun setSpan(what: Any, start: Int, end: Int, flags: Int) {
if (!CheckUtils.checkRange(this, start, end)) {
// Silently ignore
return
}
super.setSpan(what, start, end, flags)
}
}

View File

@ -0,0 +1,38 @@
/*
* 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.text
import android.text.TextPaint
import android.text.style.CharacterStyle
import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT
import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE
class TwidereHighLightStyle(private val option: Int) : CharacterStyle() {
override fun updateDrawState(ds: TextPaint) {
if (option and VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE != 0) {
ds.isUnderlineText = true
}
if (option and VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT != 0) {
ds.color = ds.linkColor
}
}
}

View File

@ -0,0 +1,38 @@
/*
* 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.text
import android.graphics.Canvas
import android.graphics.Paint
import android.text.style.ReplacementSpan
/**
* Created by mariotaku on 2017/2/11.
*/
class ZeroWidthSpan : ReplacementSpan() {
override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int {
return 0
}
override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
}
}

View File

@ -3,7 +3,10 @@ package org.mariotaku.twidere.view.holder
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.support.v7.widget.RecyclerView.ViewHolder import android.support.v7.widget.RecyclerView.ViewHolder
import android.text.* import android.text.SpannableString
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextUtils
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.view.View import android.view.View
import android.view.View.OnClickListener import android.view.View.OnClickListener
@ -16,13 +19,13 @@ import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.USER_TYPE_FANFOU_COM import org.mariotaku.twidere.TwidereConstants.USER_TYPE_FANFOU_COM
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter import org.mariotaku.twidere.adapter.iface.IStatusesAdapter
import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE
import org.mariotaku.twidere.extension.model.applyTo
import org.mariotaku.twidere.graphic.like.LikeAnimationDrawable import org.mariotaku.twidere.graphic.like.LikeAnimationDrawable
import org.mariotaku.twidere.model.ParcelableLocation import org.mariotaku.twidere.model.ParcelableLocation
import org.mariotaku.twidere.model.ParcelableMedia import org.mariotaku.twidere.model.ParcelableMedia
import org.mariotaku.twidere.model.ParcelableStatus import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.ParcelableLocationUtils import org.mariotaku.twidere.model.util.ParcelableLocationUtils
import org.mariotaku.twidere.model.util.ParcelableStatusUtils
import org.mariotaku.twidere.task.CreateFavoriteTask import org.mariotaku.twidere.task.CreateFavoriteTask
import org.mariotaku.twidere.task.DestroyFavoriteTask import org.mariotaku.twidere.task.DestroyFavoriteTask
import org.mariotaku.twidere.task.RetweetStatusTask import org.mariotaku.twidere.task.RetweetStatusTask
@ -208,7 +211,7 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
val quotedText: CharSequence val quotedText: CharSequence
if (adapter.linkHighlightingStyle != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) { if (adapter.linkHighlightingStyle != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
quotedText = SpannableStringBuilder.valueOf(status.quoted_text_unescaped) quotedText = SpannableStringBuilder.valueOf(status.quoted_text_unescaped)
ParcelableStatusUtils.applySpans(quotedText as Spannable, status.quoted_spans) status.quoted_spans?.applyTo(quotedText)
linkify.applyAllLinks(quotedText, status.account_key, layoutPosition.toLong(), linkify.applyAllLinks(quotedText, status.account_key, layoutPosition.toLong(),
status.is_possibly_sensitive, adapter.linkHighlightingStyle, status.is_possibly_sensitive, adapter.linkHighlightingStyle,
skipLinksInText) skipLinksInText)
@ -344,11 +347,12 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
val text: CharSequence val text: CharSequence
if (adapter.linkHighlightingStyle != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) { if (adapter.linkHighlightingStyle != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
text = SpannableStringBuilder.valueOf(status.text_unescaped) text = SpannableStringBuilder.valueOf(status.text_unescaped).apply {
ParcelableStatusUtils.applySpans(text as Spannable, status.spans) status.spans?.applyTo(this)
linkify.applyAllLinks(text, status.account_key, layoutPosition.toLong(), linkify.applyAllLinks(this, status.account_key, layoutPosition.toLong(),
status.is_possibly_sensitive, adapter.linkHighlightingStyle, status.is_possibly_sensitive, adapter.linkHighlightingStyle,
skipLinksInText) skipLinksInText)
}
} else { } else {
text = status.text_unescaped text = status.text_unescaped
} }

View File

@ -20,17 +20,21 @@
package org.mariotaku.twidere.view.holder.message package org.mariotaku.twidere.view.holder.message
import android.support.v4.view.GravityCompat import android.support.v4.view.GravityCompat
import android.text.SpannableStringBuilder
import android.text.format.DateUtils import android.text.format.DateUtils
import android.view.View import android.view.View
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.LinearLayout import android.widget.LinearLayout
import kotlinx.android.synthetic.main.list_item_message_conversation_text.view.* import kotlinx.android.synthetic.main.list_item_message_conversation_text.view.*
import org.mariotaku.ktextension.empty
import org.mariotaku.ktextension.isNullOrEmpty import org.mariotaku.ktextension.isNullOrEmpty
import org.mariotaku.messagebubbleview.library.MessageBubbleView import org.mariotaku.messagebubbleview.library.MessageBubbleView
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.MessagesConversationAdapter import org.mariotaku.twidere.adapter.MessagesConversationAdapter
import org.mariotaku.twidere.extension.model.applyTo
import org.mariotaku.twidere.extension.model.timestamp import org.mariotaku.twidere.extension.model.timestamp
import org.mariotaku.twidere.model.ParcelableMessage import org.mariotaku.twidere.model.ParcelableMessage
import org.mariotaku.twidere.model.SpanItem
/** /**
* Created by mariotaku on 2017/2/9. * Created by mariotaku on 2017/2/9.
@ -49,12 +53,12 @@ class MessageViewHolder(itemView: View, adapter: MessagesConversationAdapter) :
text.textSize = textSize text.textSize = textSize
time.textSize = textSize * 0.8f time.textSize = textSize * 0.8f
date.textSize = textSize * 0.9f date.textSize = textSize * 0.9f
mediaPreview.style = adapter.mediaPreviewStyle
} }
override fun display(message: ParcelableMessage, showDate: Boolean) { override fun display(message: ParcelableMessage, showDate: Boolean) {
super.display(message, showDate) super.display(message, showDate)
setOutgoingStatus(messageContent, message.is_outgoing) setOutgoingStatus(messageContent, message.is_outgoing)
text.text = message.text_unescaped
if (showDate) { if (showDate) {
date.visibility = View.VISIBLE date.visibility = View.VISIBLE
date.text = DateUtils.getRelativeTimeSpanString(message.timestamp, System.currentTimeMillis(), date.text = DateUtils.getRelativeTimeSpanString(message.timestamp, System.currentTimeMillis(),
@ -62,8 +66,49 @@ class MessageViewHolder(itemView: View, adapter: MessagesConversationAdapter) :
} else { } else {
date.visibility = View.GONE date.visibility = View.GONE
} }
// Loop through text and spans to found non-space char count
val hideText = run {
fun String.nonSpaceCount(range: IntRange): Int {
if (range.isEmpty()) return 0
return range.count { !Character.isSpaceChar(this[it]) }
}
val text = message.text_unescaped
var nonSpaceCount = 0
var curPos = 0
message.spans?.forEach { span ->
if (message.media?.firstOrNull { media -> span.link == media.url } != null) {
// Skip if span is hidden
span.type = SpanItem.SpanType.HIDE
} else {
nonSpaceCount += text.nonSpaceCount(curPos until span.end)
}
curPos = span.end
}
nonSpaceCount += text.nonSpaceCount(curPos..text.lastIndex)
return@run nonSpaceCount == 0
}
text.text = SpannableStringBuilder.valueOf(message.text_unescaped).apply {
message.spans?.applyTo(this)
adapter.linkify.applyAllLinks(this, message.account_key, layoutPosition.toLong(),
false, adapter.linkHighlightingStyle, true)
}
text.visibility = if (hideText || text.empty) {
View.GONE
} else {
View.VISIBLE
}
time.text = DateUtils.formatDateTime(adapter.context, message.timestamp, time.text = DateUtils.formatDateTime(adapter.context, message.timestamp,
DateUtils.FORMAT_SHOW_TIME) DateUtils.FORMAT_SHOW_TIME)
if (message.media.isNullOrEmpty()) { if (message.media.isNullOrEmpty()) {
mediaPreview.visibility = View.GONE mediaPreview.visibility = View.GONE
} else { } else {