basic full text expansion #843
This commit is contained in:
parent
21f5c98642
commit
b89d3c198e
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||
import android.content.SharedPreferences
|
||||
import android.support.v4.text.BidiFormatter
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.util.SparseBooleanArray
|
||||
import com.bumptech.glide.RequestManager
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.twidere.R
|
||||
|
@ -63,6 +64,7 @@ class DummyItemAdapter(
|
|||
var showCardActions: Boolean = false
|
||||
|
||||
private var showingActionCardPosition = RecyclerView.NO_POSITION
|
||||
private val showingFullTextStates = SparseBooleanArray()
|
||||
|
||||
init {
|
||||
GeneralComponent.get(context).inject(this)
|
||||
|
@ -111,6 +113,17 @@ class DummyItemAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
override fun isFullTextVisible(position: Int): Boolean {
|
||||
return showingFullTextStates.get(position)
|
||||
}
|
||||
|
||||
override fun setFullTextVisible(position: Int, visible: Boolean) {
|
||||
showingFullTextStates.put(position, visible)
|
||||
if (position != RecyclerView.NO_POSITION && adapter != null) {
|
||||
adapter.notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getUser(position: Int): ParcelableUser? {
|
||||
if (adapter is ParcelableUsersAdapter) {
|
||||
return adapter.getUser(position)
|
||||
|
|
|
@ -23,9 +23,11 @@ import android.content.Context
|
|||
import android.database.CursorIndexOutOfBoundsException
|
||||
import android.support.v4.widget.Space
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.util.SparseBooleanArray
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import com.bumptech.glide.RequestManager
|
||||
import org.apache.commons.collections.primitives.ArrayLongList
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.*
|
||||
import org.mariotaku.library.objectcursor.ObjectCursor
|
||||
|
@ -118,6 +120,7 @@ abstract class ParcelableStatusesAdapter(
|
|||
private var displayPositions: IntArray? = null
|
||||
private var displayDataCount: Int = 0
|
||||
private var showingActionCardId = RecyclerView.NO_ID
|
||||
private val showingFullTextStates = SparseBooleanArray()
|
||||
private val reuseStatus = ParcelableStatus()
|
||||
private var infoCache: Array<StatusInfo?>? = null
|
||||
|
||||
|
@ -284,6 +287,17 @@ abstract class ParcelableStatusesAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
override fun isFullTextVisible(position: Int): Boolean {
|
||||
return showingFullTextStates.get(position)
|
||||
}
|
||||
|
||||
override fun setFullTextVisible(position: Int, visible: Boolean) {
|
||||
showingFullTextStates.put(position, visible)
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
when (viewType) {
|
||||
ITEM_VIEW_TYPE_GAP -> {
|
||||
|
|
|
@ -37,6 +37,10 @@ interface IStatusesAdapter<in Data> : IContentAdapter, IGapSupportedAdapter {
|
|||
|
||||
fun showCardActions(position: Int)
|
||||
|
||||
fun isFullTextVisible(position: Int): Boolean
|
||||
|
||||
fun setFullTextVisible(position: Int, visible: Boolean)
|
||||
|
||||
fun setData(data: Data?): Boolean
|
||||
|
||||
/**
|
||||
|
|
|
@ -49,6 +49,7 @@ import android.text.Spanned
|
|||
import android.text.TextUtils
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.util.SparseBooleanArray
|
||||
import android.view.*
|
||||
import android.view.View.OnClickListener
|
||||
import android.widget.Space
|
||||
|
@ -1447,7 +1448,8 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
private var replyError: CharSequence? = null
|
||||
private var conversationError: CharSequence? = null
|
||||
private var replyStart: Int = 0
|
||||
private var showingActionCardPosition: Int = 0
|
||||
private var showingActionCardPosition = RecyclerView.NO_POSITION
|
||||
private val showingFullTextStates = SparseBooleanArray()
|
||||
|
||||
init {
|
||||
setHasStableIds(true)
|
||||
|
@ -1532,6 +1534,16 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
|||
}
|
||||
}
|
||||
|
||||
override fun isFullTextVisible(position: Int): Boolean {
|
||||
return showingFullTextStates.get(position)
|
||||
}
|
||||
|
||||
override fun setFullTextVisible(position: Int, visible: Boolean) {
|
||||
showingFullTextStates.put(position, visible)
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
override fun setData(data: List<ParcelableStatus>?): Boolean {
|
||||
val status = this.status ?: return false
|
||||
val changed = this.data != data
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package org.mariotaku.twidere.text
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.text.TextPaint
|
||||
import android.text.style.ReplacementSpan
|
||||
|
||||
/**
|
||||
* Created by Mariotaku on 2017/5/21.
|
||||
*/
|
||||
|
||||
class ShowMoreToggleSpan: ReplacementSpan() {
|
||||
|
||||
override fun getSize(paint: Paint?, text: CharSequence?, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun draw(canvas: Canvas?, text: CharSequence?, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint?) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.mariotaku.twidere.text
|
||||
|
||||
import android.text.TextPaint
|
||||
import android.text.style.ClickableSpan
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants
|
||||
|
||||
/**
|
||||
* Created by Mariotaku on 2017/5/21.
|
||||
*/
|
||||
|
||||
abstract class TwidereClickableSpan(val highlightStyle: Int): ClickableSpan() {
|
||||
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
if (SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE in highlightStyle) {
|
||||
ds.isUnderlineText = true
|
||||
}
|
||||
if (SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT in highlightStyle) {
|
||||
ds.color = ds.linkColor
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import android.support.v7.widget.RecyclerView.ViewHolder
|
|||
import android.text.SpannableString
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.style.ClickableSpan
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.view.View
|
||||
|
@ -37,6 +38,7 @@ import org.mariotaku.twidere.model.UserKey
|
|||
import org.mariotaku.twidere.task.CreateFavoriteTask
|
||||
import org.mariotaku.twidere.task.DestroyFavoriteTask
|
||||
import org.mariotaku.twidere.task.RetweetStatusTask
|
||||
import org.mariotaku.twidere.text.TwidereClickableSpan
|
||||
import org.mariotaku.twidere.util.*
|
||||
import org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText
|
||||
import org.mariotaku.twidere.util.Utils.getUserTypeIconRes
|
||||
|
@ -109,7 +111,7 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
|||
adapter.profileImageStyle, profileImageView.cornerRadius,
|
||||
profileImageView.cornerRadiusRatio).into(profileImageView)
|
||||
nameView.name = TWIDERE_PREVIEW_NAME
|
||||
nameView.screenName = "@" + TWIDERE_PREVIEW_SCREEN_NAME
|
||||
nameView.screenName = "@$TWIDERE_PREVIEW_SCREEN_NAME"
|
||||
nameView.updateText(adapter.bidiFormatter)
|
||||
summaryView.hideIfEmpty()
|
||||
if (adapter.linkHighlightingStyle == VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
|
||||
|
@ -154,8 +156,8 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
|||
statusContentLowerSpace.visibility = if (showCardActions) View.GONE else View.VISIBLE
|
||||
|
||||
val replyCount = status.reply_count
|
||||
val retweetCount: Long
|
||||
val favoriteCount: Long
|
||||
val retweetCount = status.retweet_count
|
||||
val favoriteCount = status.favorite_count
|
||||
|
||||
if (displayPinned && status.is_pinned_status) {
|
||||
statusInfoLabel.setText(R.string.pinned_status)
|
||||
|
@ -232,13 +234,7 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
|||
} else {
|
||||
quotedTextView.spannable = quotedText
|
||||
}
|
||||
|
||||
if (quotedTextView.length() == 0) {
|
||||
// No text
|
||||
quotedTextView.visibility = View.GONE
|
||||
} else {
|
||||
quotedTextView.visibility = View.VISIBLE
|
||||
}
|
||||
quotedTextView.hideIfEmpty()
|
||||
|
||||
val quoted_user_color = colorNameManager.getUserColor(quoted_user_key)
|
||||
if (quoted_user_color != 0) {
|
||||
|
@ -361,11 +357,13 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
|||
|
||||
val text: CharSequence
|
||||
val displayEnd: Int
|
||||
if (!summaryView.empty) {
|
||||
if (!summaryView.empty && !isFullTextVisible) {
|
||||
text = SpannableStringBuilder.valueOf(context.getString(R.string.label_status_show_more)).apply {
|
||||
val colorSecondary = ThemeUtils.getTextColorSecondary(context)
|
||||
setSpan(ForegroundColorSpan(colorSecondary), 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
setSpan(StyleSpan(Typeface.ITALIC), 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
setSpan(object : TwidereClickableSpan(adapter.linkHighlightingStyle) {
|
||||
override fun onClick(widget: View?) {
|
||||
showFullText()
|
||||
}
|
||||
}, 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
displayEnd = -1
|
||||
} else if (adapter.linkHighlightingStyle != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
|
||||
|
@ -415,7 +413,6 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
|||
Utils.isMyRetweet(status.account_key, status.retweeted_by_user_key,
|
||||
status.my_retweet_id)
|
||||
}
|
||||
retweetCount = status.retweet_count
|
||||
|
||||
if (retweetCount > 0) {
|
||||
retweetCountView.spannable = UnitConvertUtils.calculateProperCount(retweetCount)
|
||||
|
@ -430,7 +427,6 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
|||
val creatingFavorite = CreateFavoriteTask.isCreatingFavorite(status.account_key, status.id)
|
||||
favoriteIcon.isActivated = creatingFavorite || status.is_favorite
|
||||
}
|
||||
favoriteCount = status.favorite_count
|
||||
|
||||
if (favoriteCount > 0) {
|
||||
favoriteCountView.spannable = UnitConvertUtils.calculateProperCount(favoriteCount)
|
||||
|
@ -590,6 +586,9 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
|||
private val isCardActionsShown: Boolean
|
||||
get() = adapter.isCardActionsShown(layoutPosition)
|
||||
|
||||
private val isFullTextVisible: Boolean
|
||||
get() = adapter.isFullTextVisible(layoutPosition)
|
||||
|
||||
private fun showCardActions() {
|
||||
adapter.showCardActions(layoutPosition)
|
||||
}
|
||||
|
@ -599,6 +598,15 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
|||
return !adapter.isCardActionsShown(RecyclerView.NO_POSITION)
|
||||
}
|
||||
|
||||
private fun showFullText() {
|
||||
adapter.setFullTextVisible(layoutPosition, true)
|
||||
}
|
||||
|
||||
private fun hideFullText(): Boolean {
|
||||
adapter.setFullTextVisible(layoutPosition, false)
|
||||
return !adapter.isFullTextVisible(RecyclerView.NO_POSITION)
|
||||
}
|
||||
|
||||
private fun TextView.displayMediaLabel(cardName: String?, media: Array<ParcelableMedia?>?,
|
||||
location: ParcelableLocation?, placeFullName: String?,
|
||||
sensitive: Boolean) {
|
||||
|
|
Loading…
Reference in New Issue