improved DM item - hides text when there's only media
This commit is contained in:
parent
f665318eb6
commit
d819fa9bd1
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue