improved status list item placeholder

migrating status list item to ConstraintLayout implementation
This commit is contained in:
Mariotaku Lee 2017-12-30 06:41:41 +08:00
parent 6e71aabc10
commit d728a86f17
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
13 changed files with 564 additions and 375 deletions

View File

@ -114,6 +114,7 @@ android {
sourceSets.each {
it.res.srcDirs += project.files("src/${it.name}/res-localized")
it.res.srcDirs += project.files("src/${it.name}/res-svg2png")
it.res.srcDirs += project.files("src/${it.name}/res-preview")
it.java.srcDirs += "src/${it.name}/kotlin"
}

View File

@ -50,6 +50,7 @@ import org.mariotaku.twidere.model.ItemCounts
import org.mariotaku.twidere.model.ObjectId
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.placeholder.ParcelableStatusPlaceholder
import org.mariotaku.twidere.model.timeline.TimelineFilter
import org.mariotaku.twidere.util.StatusAdapterLinkClickHandler
import org.mariotaku.twidere.util.TwidereLinkify
@ -168,11 +169,11 @@ class ParcelableStatusesAdapter(
}
override fun isGapItem(position: Int): Boolean {
return getStatusInternal(false, false, position = position)?.is_gap == true
return getStatusInternal(false, false, position = position).is_gap
}
override fun getStatus(position: Int, raw: Boolean): ParcelableStatus {
return getStatusInternal(raw, position = position) ?: ParcelableStatusPlaceholder
return getStatusInternal(raw, position = position)
}
override fun getStatusCount(raw: Boolean): Int {
@ -290,7 +291,7 @@ class ParcelableStatusesAdapter(
holder as IStatusViewHolder
val countIndex: Int = getItemCountIndex(position)
val status = getStatusInternal(loadAround = true, position = position,
countIndex = countIndex) ?: return
countIndex = countIndex)
holder.display(status, displayInReplyTo = isShowInReplyTo,
displayPinned = countIndex == ITEM_INDEX_PINNED_STATUS)
}
@ -298,7 +299,7 @@ class ParcelableStatusesAdapter(
(holder as TimelineFilterHeaderViewHolder).display(timelineFilter!!)
}
ITEM_VIEW_TYPE_GAP -> {
val status = getStatusInternal(loadAround = true, position = position) ?: return
val status = getStatusInternal(loadAround = true, position = position)
val loading = gapLoadingIds.any { it.accountKey == status.account_key && it.id == status.id }
(holder as GapViewHolder).display(loading)
}
@ -396,7 +397,7 @@ class ParcelableStatusesAdapter(
}
private fun getStatusInternal(raw: Boolean = false, loadAround: Boolean = false,
position: Int, countIndex: Int = getItemCountIndex(position, raw)): ParcelableStatus? {
position: Int, countIndex: Int = getItemCountIndex(position, raw)): ParcelableStatus {
when (countIndex) {
ITEM_INDEX_PINNED_STATUS -> {
return pinnedStatuses!![position - getItemStartPosition(ITEM_INDEX_PINNED_STATUS)]
@ -404,9 +405,9 @@ class ParcelableStatusesAdapter(
ITEM_INDEX_STATUS -> {
val dataPosition = position - statusStartIndex
return if (loadAround) {
pagedStatusesHelper.getItem(dataPosition)
pagedStatusesHelper.getItem(dataPosition) ?: ParcelableStatusPlaceholder
} else {
pagedStatusesHelper.currentList?.get(dataPosition)
pagedStatusesHelper.currentList?.get(dataPosition) ?: ParcelableStatusPlaceholder
}
}
}
@ -422,18 +423,6 @@ class ParcelableStatusesAdapter(
itemCounts[ITEM_INDEX_LOAD_END_INDICATOR] = if (LoadMorePosition.END in loadMoreIndicatorPosition) 1 else 0
}
object ParcelableStatusPlaceholder : ParcelableStatus() {
init {
id = "none"
account_key = UserKey.INVALID
user_key = UserKey.INVALID
}
override fun hashCode(): Int {
return -1
}
}
companion object {
const val VIEW_TYPE_STATUS = 2
const val VIEW_TYPE_EMPTY = 3

View File

@ -0,0 +1,35 @@
/*
* 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.model.placeholder
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey
object ParcelableStatusPlaceholder : ParcelableStatus() {
init {
id = "none"
account_key = UserKey.INVALID
user_key = UserKey.INVALID
}
override fun hashCode(): Int {
return -1
}
}

View File

@ -69,7 +69,7 @@ class CardPreviewPreference(
}
this.holder?.let {
it.setupViewOptions()
it.displaySampleStatus()
it.preview()
}
super.onBindViewHolder(holder)
}

View File

@ -2,14 +2,11 @@ package org.mariotaku.twidere.text
import android.text.TextPaint
import android.text.style.ClickableSpan
import android.view.View
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() {
class TwidereClickableSpan(val highlightStyle: Int, val callback: () -> Unit) : ClickableSpan() {
override fun updateDrawState(ds: TextPaint) {
if (SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE in highlightStyle) {
@ -19,4 +16,8 @@ abstract class TwidereClickableSpan(val highlightStyle: Int): ClickableSpan() {
ds.color = ds.linkColor
}
}
override fun onClick(widget: View?) {
callback()
}
}

View File

@ -0,0 +1,58 @@
/*
* 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.style
import android.graphics.Canvas
import android.graphics.Paint
import android.text.style.ReplacementSpan
class PlaceholderLineSpan(val width: Float, val widthRelativeToChar: Boolean = false) : ReplacementSpan() {
private val fontMetrics = Paint.FontMetrics()
override fun getSize(paint: Paint, text: CharSequence?, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int {
paint.getFontMetrics(fontMetrics)
if (fm != null) {
paint.getFontMetricsInt(fm)
}
return if (widthRelativeToChar) {
(width * paint.textSize).toInt()
} else {
100
}
}
override fun draw(canvas: Canvas, text: CharSequence?, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
val width = if (widthRelativeToChar) {
width * paint.textSize
} else {
(canvas.width - x) * width
}
val paintAlphaBackup = paint.alpha
paint.alpha = placeholderAlpha
canvas.drawRect(x, top + fontMetrics.leading, x + width, bottom - fontMetrics.descent,
paint)
paint.alpha = paintAlphaBackup
}
companion object {
const val placeholderAlpha = 0x20
}
}

View File

@ -0,0 +1,71 @@
/*
* 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.view
import android.content.Context
import android.graphics.Canvas
import android.support.constraint.ConstraintLayout
import android.util.AttributeSet
import org.mariotaku.twidere.view.iface.IColorLabelView
class ColorLabelConstraintLayout(context: Context, attrs: AttributeSet? = null) : ConstraintLayout(context, attrs), IColorLabelView {
private val helper = IColorLabelView.Helper(this, context, attrs, 0)
override fun drawBackground(color: Int) {
helper.drawBackground(color)
}
override fun drawBottom(vararg colors: Int) {
helper.drawBottom(colors)
}
override fun drawEnd(vararg colors: Int) {
helper.drawEnd(colors)
}
override fun drawLabel(start: IntArray, end: IntArray, top: IntArray, bottom: IntArray, background: Int) {
helper.drawLabel(start, end, top, bottom, background)
}
override fun drawStart(vararg colors: Int) {
helper.drawStart(colors)
}
override fun drawTop(vararg colors: Int) {
helper.drawTop(colors)
}
override fun isPaddingIgnored(): Boolean {
return helper.isPaddingIgnored
}
override fun setIgnorePadding(ignorePadding: Boolean) {
helper.setIgnorePadding(ignorePadding)
}
override fun dispatchDraw(canvas: Canvas) {
helper.dispatchDrawBackground(canvas)
super.dispatchDraw(canvas)
helper.dispatchDrawLabels(canvas)
}
}

View File

@ -24,10 +24,13 @@ import android.os.Handler
import android.os.HandlerThread
import android.os.SystemClock
import android.support.v7.widget.AppCompatTextView
import android.text.Spannable
import android.text.SpannableString
import android.text.format.DateUtils
import android.util.AttributeSet
import org.mariotaku.twidere.Constants
import org.mariotaku.twidere.R
import org.mariotaku.twidere.text.style.PlaceholderLineSpan
import org.mariotaku.twidere.util.Utils.formatSameDayTime
import java.lang.ref.WeakReference
import java.util.concurrent.TimeUnit
@ -40,6 +43,8 @@ class ShortTimeView(
private val ticker = TickerRunnable(this)
private val invalidateTimeRunnable = Runnable {
val time = this.time
if (time < 0) return@Runnable
val label = getTimeLabel(context, time, showAbsoluteTime)
post {
setTextIfChanged(label)
@ -52,7 +57,7 @@ class ShortTimeView(
invalidateTime()
}
var time: Long = 0
var time: Long = -1
set(value) {
field = value
invalidateTime()
@ -69,7 +74,11 @@ class ShortTimeView(
}
private fun invalidateTime() {
updateHandler.post(invalidateTimeRunnable)
if (time == PLACEHOLDER) {
text = placeholderText
} else {
updateHandler.post(invalidateTimeRunnable)
}
}
private fun setTextIfChanged(text: CharSequence?) {
@ -93,6 +102,13 @@ class ShortTimeView(
companion object {
const val INVALID: Long = -1
const val PLACEHOLDER: Long = -2
private val placeholderText = SpannableString(" ").apply {
setSpan(PlaceholderLineSpan(3.5f, true), 0, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
private const val TICKER_DURATION = 5000L
private val ONE_MINUTE_MILLIS = TimeUnit.MINUTES.toMillis(1)

View File

@ -23,14 +23,13 @@ import android.content.Context
import android.content.res.Resources
import android.support.annotation.Dimension
import android.support.v4.text.BidiFormatter
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextUtils
import android.text.*
import android.text.style.TextAppearanceSpan
import android.util.AttributeSet
import android.util.TypedValue
import org.mariotaku.twidere.R
import org.mariotaku.twidere.model.theme.TextAppearance
import org.mariotaku.twidere.text.style.PlaceholderLineSpan
open class TwoLineTextView(context: Context, attrs: AttributeSet? = null) : FixedTextView(context, attrs) {
@ -46,6 +45,8 @@ open class TwoLineTextView(context: Context, attrs: AttributeSet? = null) : Fixe
var primaryText: CharSequence? = null
var secondaryText: CharSequence? = null
var placeholder: Boolean = false
protected open val displayPrimaryText: CharSequence?
get() = primaryText
@ -93,6 +94,10 @@ open class TwoLineTextView(context: Context, attrs: AttributeSet? = null) : Fixe
}
fun updateText(formatter: BidiFormatter? = null) {
if (placeholder) {
text = placeholderText
return
}
val sb = SpannableStringBuilder()
val primaryText = displayPrimaryText
val secondaryText = displaySecondaryText
@ -131,4 +136,10 @@ open class TwoLineTextView(context: Context, attrs: AttributeSet? = null) : Fixe
return TypedValue.applyDimension(unit, size, r.displayMetrics)
}
companion object {
private val placeholderText = SpannableString(" ").apply {
setSpan(PlaceholderLineSpan(0.6f), 0, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
}

View File

@ -30,9 +30,6 @@ import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.view.CardMediaContainer
import org.mariotaku.twidere.view.holder.TimelineFilterHeaderViewHolder
/**
* Created by mariotaku on 15/10/26.
*/
interface IStatusViewHolder : CardMediaContainer.OnMediaClickListener {
fun display(status: ParcelableStatus, displayInReplyTo: Boolean = true,

View File

@ -48,22 +48,26 @@ import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHL
import org.mariotaku.twidere.extension.loadProfileImage
import org.mariotaku.twidere.extension.model.*
import org.mariotaku.twidere.extension.setVisible
import org.mariotaku.twidere.extension.text.appendCompat
import org.mariotaku.twidere.graphic.like.LikeAnimationDrawable
import org.mariotaku.twidere.model.ParcelableLocation
import org.mariotaku.twidere.model.ParcelableMedia
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.placeholder.ParcelableStatusPlaceholder
import org.mariotaku.twidere.task.CreateFavoriteTask
import org.mariotaku.twidere.task.DestroyFavoriteTask
import org.mariotaku.twidere.task.DestroyStatusTask
import org.mariotaku.twidere.task.RetweetStatusTask
import org.mariotaku.twidere.text.TwidereClickableSpan
import org.mariotaku.twidere.text.style.PlaceholderLineSpan
import org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText
import org.mariotaku.twidere.util.HtmlSpanBuilder
import org.mariotaku.twidere.util.ThemeUtils
import org.mariotaku.twidere.util.UnitConvertUtils
import org.mariotaku.twidere.util.Utils.getUserTypeIconRes
import org.mariotaku.twidere.view.ShapedImageView
import org.mariotaku.twidere.view.ShortTimeView
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder
/**
@ -71,35 +75,40 @@ import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder
*/
class StatusViewHolder(private val adapter: IStatusesAdapter, itemView: View) : ViewHolder(itemView), IStatusViewHolder {
override val profileImageView: ShapedImageView by lazy { itemView.profileImage }
override val profileTypeView: ImageView by lazy { itemView.profileType }
override val profileImageView: ShapedImageView = itemView.profileImage
override val profileTypeView: ImageView = itemView.profileType
private val itemContent by lazy { itemView.itemContent }
private val mediaPreview by lazy { itemView.mediaPreview }
private val statusContentUpperSpace by lazy { itemView.statusContentUpperSpace }
private val summaryView by lazy { itemView.summary }
private val textView by lazy { itemView.text }
private val nameView by lazy { itemView.name }
private val itemMenu by lazy { itemView.itemMenu }
private val statusInfoLabel by lazy { itemView.statusInfoLabel }
private val statusInfoIcon by lazy { itemView.statusInfoIcon }
private val quotedNameView by lazy { itemView.quotedName }
private val timeView by lazy { itemView.time }
private val quotedView by lazy { itemView.quotedView }
private val quotedTextView by lazy { itemView.quotedText }
private val actionButtons by lazy { itemView.actionButtons }
private val mediaLabel by lazy { itemView.mediaLabel }
private val quotedMediaLabel by lazy { itemView.quotedMediaLabel }
private val statusContentLowerSpace by lazy { itemView.statusContentLowerSpace }
private val quotedMediaPreview by lazy { itemView.quotedMediaPreview }
private val replyButton by lazy { itemView.reply }
private val retweetButton by lazy { itemView.retweet }
private val favoriteButton by lazy { itemView.favorite }
private val itemContent = itemView.itemContent
private val mediaPreview = itemView.mediaPreview
private val summaryView = itemView.summary
private val textView = itemView.text
private val nameView = itemView.name
private val itemMenu = itemView.itemMenu
private val statusInfoLabel = itemView.statusInfoLabel
private val statusInfoIcon = itemView.statusInfoIcon
private val quotedNameView = itemView.quotedName
private val timeView = itemView.time
private val quotedView = itemView.quotedView
private val quotedTextView = itemView.quotedText
private val mediaLabel = itemView.mediaLabel
private val quotedMediaLabel = itemView.quotedMediaLabel
private val quotedMediaPreview = itemView.quotedMediaPreview
private val replyButton = itemView.reply
private val retweetButton = itemView.retweet
private val favoriteButton = itemView.favorite
private val eventHandler = EventHandler()
private var statusClickListener: IStatusViewHolder.StatusClickListener? = null
private val toggleFullTextSpan = TwidereClickableSpan(adapter.linkHighlightingStyle) {
if (adapter.isFullTextVisible(layoutPosition)) {
hideFullText()
} else {
showFullText()
}
}
init {
if (adapter.mediaPreviewEnabled) {
@ -111,11 +120,9 @@ class StatusViewHolder(private val adapter: IStatusesAdapter, itemView: View) :
}
fun displaySampleStatus() {
fun preview() {
val profileImageEnabled = adapter.profileImageEnabled
profileImageView.visibility = if (profileImageEnabled) View.VISIBLE else View.GONE
statusContentUpperSpace.visibility = View.VISIBLE
adapter.requestManager.loadProfileImage(itemView.context, R.drawable.ic_profile_image_twidere,
adapter.profileImageStyle, profileImageView.cornerRadius,
@ -141,15 +148,57 @@ class StatusViewHolder(private val adapter: IStatusesAdapter, itemView: View) :
mediaPreview.visibility = View.GONE
mediaLabel.visibility = View.VISIBLE
}
actionButtons.visibility = if (showCardActions) View.VISIBLE else View.GONE
itemMenu.visibility = if (showCardActions) View.VISIBLE else View.GONE
statusContentLowerSpace.visibility = if (showCardActions) View.GONE else View.VISIBLE
quotedMediaPreview.visibility = View.GONE
quotedMediaLabel.visibility = View.GONE
replyButton.setVisible(showCardActions)
retweetButton.setVisible(showCardActions)
favoriteButton.setVisible(showCardActions)
itemMenu.setVisible(showCardActions)
quotedView.visibility = View.GONE
mediaPreview.displayMedia(R.drawable.featured_graphics)
}
fun placeholder() {
val context = itemView.context
val requestManager = adapter.requestManager
requestManager.loadProfileImage(context, R.drawable.ic_profile_image_placeholder, adapter.profileImageStyle,
profileImageView.cornerRadius, profileImageView.cornerRadiusRatio).into(profileImageView)
timeView.time = ShortTimeView.PLACEHOLDER
textView.spannable = placeholderText
nameView.placeholder = true
nameView.updateText()
val actionButtonsAlpha = PlaceholderLineSpan.placeholderAlpha / 255f
replyButton.alpha = actionButtonsAlpha
retweetButton.alpha = actionButtonsAlpha
favoriteButton.alpha = actionButtonsAlpha
itemMenu.alpha = actionButtonsAlpha
replyButton.isActivated = false
retweetButton.isActivated = false
favoriteButton.isActivated = false
replyButton.text = null
retweetButton.text = null
favoriteButton.text = null
profileTypeView.visibility = View.GONE
summaryView.visibility = View.GONE
mediaLabel.visibility = View.GONE
mediaPreview.visibility = View.GONE
quotedView.visibility = View.GONE
statusInfoIcon.visibility = View.GONE
statusInfoLabel.visibility = View.GONE
}
override fun display(status: ParcelableStatus, displayInReplyTo: Boolean, displayPinned: Boolean) {
if (status === ParcelableStatusPlaceholder) {
placeholder()
return
}
val context = itemView.context
val requestManager = adapter.requestManager
val linkify = adapter.twidereLinkify
@ -157,9 +206,15 @@ class StatusViewHolder(private val adapter: IStatusesAdapter, itemView: View) :
val colorNameManager = adapter.userColorNameManager
val showCardActions = isCardActionsShown
actionButtons.visibility = if (showCardActions) View.VISIBLE else View.GONE
itemMenu.visibility = if (showCardActions) View.VISIBLE else View.GONE
statusContentLowerSpace.visibility = if (showCardActions) View.GONE else View.VISIBLE
replyButton.alpha = 1f
retweetButton.alpha = 1f
favoriteButton.alpha = 1f
itemMenu.alpha = 1f
replyButton.setVisible(showCardActions)
retweetButton.setVisible(showCardActions)
favoriteButton.setVisible(showCardActions)
itemMenu.setVisible(showCardActions)
val replyCount = status.reply_count
val retweetCount = status.retweet_count
@ -170,8 +225,6 @@ class StatusViewHolder(private val adapter: IStatusesAdapter, itemView: View) :
statusInfoIcon.setImageResource(R.drawable.ic_activity_action_pinned)
statusInfoLabel.visibility = View.VISIBLE
statusInfoIcon.visibility = View.VISIBLE
statusContentUpperSpace.visibility = View.GONE
} else if (status.retweet_id != null) {
val retweetedBy = colorNameManager.getDisplayName(status.retweeted_by_user_key!!,
status.retweeted_by_user_name, status.retweeted_by_user_acct!!)
@ -179,8 +232,6 @@ class StatusViewHolder(private val adapter: IStatusesAdapter, itemView: View) :
statusInfoIcon.setImageResource(R.drawable.ic_activity_action_retweet)
statusInfoLabel.visibility = View.VISIBLE
statusInfoIcon.visibility = View.VISIBLE
statusContentUpperSpace.visibility = View.GONE
} else if (status.in_reply_to_status_id != null && status.in_reply_to_user_key != null && displayInReplyTo) {
if (status.in_reply_to_name != null && status.in_reply_to_screen_name != null) {
val inReplyTo = colorNameManager.getDisplayName(status.in_reply_to_user_key!!,
@ -192,13 +243,9 @@ class StatusViewHolder(private val adapter: IStatusesAdapter, itemView: View) :
statusInfoIcon.setImageResource(R.drawable.ic_activity_action_reply)
statusInfoLabel.visibility = View.VISIBLE
statusInfoIcon.visibility = View.VISIBLE
statusContentUpperSpace.visibility = View.GONE
} else {
statusInfoLabel.visibility = View.GONE
statusInfoIcon.visibility = View.GONE
statusContentUpperSpace.visibility = View.VISIBLE
}
val skipLinksInText = status.extras?.support_entities ?: false
@ -296,6 +343,7 @@ class StatusViewHolder(private val adapter: IStatusesAdapter, itemView: View) :
status.timestamp
}
nameView.placeholder = false
nameView.name = colorNameManager.getUserNickname(status.user_key, status.user_name)
nameView.screenName = "@${status.user_acct}"
@ -356,11 +404,7 @@ class StatusViewHolder(private val adapter: IStatusesAdapter, itemView: View) :
val displayEnd: Int
if (!summaryView.empty && !isFullTextVisible) {
text = SpannableStringBuilder.valueOf(context.getString(R.string.label_status_show_more)).apply {
setSpan(object : TwidereClickableSpan(adapter.linkHighlightingStyle) {
override fun onClick(widget: View?) {
showFullText()
}
}, 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
setSpan(toggleFullTextSpan, 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
displayEnd = -1
} else if (adapter.linkHighlightingStyle != VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
@ -665,8 +709,8 @@ class StatusViewHolder(private val adapter: IStatusesAdapter, itemView: View) :
}
private fun TextView.setLabelIcon(@DrawableRes icon: Int) {
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, icon, 0,
0, 0)
TextViewCompat.setCompoundDrawablesRelative(this, ContextCompat.getDrawable(context, icon),
null, null, null)
}
private val Array<ParcelableMedia?>.type: Int
@ -744,6 +788,16 @@ class StatusViewHolder(private val adapter: IStatusesAdapter, itemView: View) :
private val videoTypes = intArrayOf(ParcelableMedia.Type.VIDEO, ParcelableMedia.Type.ANIMATED_GIF,
ParcelableMedia.Type.EXTERNAL_PLAYER)
private val placeholderText = SpannableStringBuilder().apply {
appendCompat(" ", PlaceholderLineSpan(1f), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
appendln()
appendCompat(" ", PlaceholderLineSpan(1f), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
appendln()
appendCompat(" ", PlaceholderLineSpan(1f), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
appendln()
appendCompat(" ", PlaceholderLineSpan(.5f), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
fun isRetweetIconActivated(status: ParcelableStatus): Boolean {
return !DestroyStatusTask.isRunning(status.account_key, status.my_retweet_id) &&
(RetweetStatusTask.isRunning(status.account_key, status.id) ||

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/material_blue_grey"/>
<size
android:width="72dp"
android:height="72dp"/>
</shape>

View File

@ -1,22 +1,22 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
~ 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/>.
-->
<org.mariotaku.twidere.view.ColorLabelRelativeLayout
<org.mariotaku.twidere.view.ColorLabelConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
@ -38,32 +38,26 @@
style="?profileImageStyle"
android:layout_width="@dimen/element_size_small"
android:layout_height="@dimen/element_size_small"
android:layout_alignBottom="@+id/statusInfoLabel"
android:layout_alignEnd="@+id/profileImage"
android:layout_alignRight="@+id/profileImage"
android:layout_alignTop="@+id/statusInfoLabel"
android:padding="@dimen/element_spacing_small"
android:scaleType="centerInside"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@+id/profileImage"
app:tint="?android:textColorSecondary"
tools:src="@drawable/ic_activity_action_retweet"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.FixedTextView
android:id="@+id/statusInfoLabel"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginStart="@dimen/element_spacing_normal"
android:layout_toEndOf="@+id/statusInfoIcon"
android:layout_toRightOf="@+id/statusInfoIcon"
android:ellipsize="end"
android:gravity="center_vertical|start"
android:maxLines="1"
android:minHeight="@dimen/element_size_small"
android:textAppearance="?android:attr/textAppearanceSmall"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/name"
tools:text="Retweeted by Mariotaku"
tools:textSize="@dimen/text_size_extra_small"
tools:visibility="visible"/>
@ -73,15 +67,9 @@
style="?profileImageStyle"
android:layout_width="@dimen/icon_size_status_profile_image"
android:layout_height="@dimen/icon_size_status_profile_image"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignTop="@+id/statusContent"
android:layout_alignWithParentIfMissing="true"
android:layout_below="@+id/statusInfoLabel"
android:layout_marginBottom="@dimen/element_spacing_normal"
android:layout_marginEnd="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_normal"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/name"
tools:ignore="ContentDescription"
tools:src="@drawable/ic_profile_image_twidere"
tools:visibility="visible"/>
@ -90,318 +78,258 @@
android:id="@+id/profileType"
android:layout_width="@dimen/icon_size_profile_type"
android:layout_height="@dimen/icon_size_profile_type"
android:layout_alignBottom="@+id/profileImage"
android:layout_alignEnd="@+id/profileImage"
android:layout_alignRight="@+id/profileImage"
android:layout_marginBottom="@dimen/element_spacing_minus_small"
android:layout_marginEnd="@dimen/element_spacing_minus_small"
android:layout_marginRight="@dimen/element_spacing_minus_small"
android:scaleType="fitCenter"
app:layout_constraintBottom_toBottomOf="@+id/profileImage"
app:layout_constraintEnd_toEndOf="@+id/profileImage"
tools:src="@drawable/ic_user_type_verified"
tools:visibility="visible"/>
<Space
android:id="@+id/statusContentUpperSpace"
android:layout_width="match_parent"
android:layout_height="@dimen/element_spacing_normal"
android:layout_below="@+id/statusInfoLabel"
android:visibility="gone"/>
<RelativeLayout
android:id="@+id/statusContent"
android:layout_width="match_parent"
<org.mariotaku.twidere.view.NameView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_below="@+id/statusContentUpperSpace"
android:layout_toEndOf="@+id/profileImage"
android:layout_toRightOf="@+id/profileImage">
android:layout_marginEnd="@dimen/element_spacing_small"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_small"
android:layout_marginStart="@dimen/element_spacing_normal"
android:ellipsize="end"
android:maxLines="1"
app:layout_constraintEnd_toStartOf="@+id/time"
app:layout_constraintStart_toEndOf="@+id/profileImage"
app:layout_constraintTop_toBottomOf="@+id/statusInfoLabel"
app:layout_goneMarginStart="0dp"
app:layout_goneMarginTop="@dimen/element_spacing_normal"
app:tltvPrimaryTextAppearance="?android:textAppearanceSmall"
app:tltvPrimaryTextColor="?android:textColorPrimary"
app:tltvPrimaryTextStyle="bold"
app:tltvSecondaryTextAppearance="?android:textAppearanceSmall"
app:tltvSecondaryTextColor="?android:textColorSecondary"
tools:tltvPrimaryText="Name"
tools:tltvSecondaryText="\@screenname"/>
<org.mariotaku.twidere.view.ShortTimeView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearanceSmall"
app:layout_constraintBaseline_toBaselineOf="@+id/name"
app:layout_constraintEnd_toEndOf="parent"
tools:text="42 mins ago"
tools:textSize="@dimen/text_size_extra_small"/>
<org.mariotaku.twidere.view.TimelineContentTextView
android:id="@+id/summary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingTop="@dimen/element_spacing_small"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/name"
app:layout_constraintTop_toBottomOf="@+id/name"
tools:text="@string/sample_summary_text"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.TimelineContentTextView
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingTop="@dimen/element_spacing_small"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/name"
app:layout_constraintTop_toBottomOf="@+id/summary"
tools:text="@string/sample_status_text"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.DrawableTintTextView
android:id="@+id/mediaLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/element_spacing_xsmall"
android:background="?selectableItemBackground"
android:drawableLeft="@drawable/ic_label_gallery"
android:drawableStart="@drawable/ic_label_gallery"
android:gravity="center_vertical"
android:minHeight="@dimen/element_size_small"
android:textAppearance="?android:textAppearanceSmall"
android:textStyle="bold"
app:drawableTint="?android:textColorSecondary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/name"
app:layout_constraintTop_toBottomOf="@+id/text"
tools:text="@string/label_media"/>
<org.mariotaku.twidere.view.CardMediaContainer
android:id="@+id/mediaPreview"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/element_spacing_xsmall"
android:horizontalSpacing="@dimen/element_spacing_xsmall"
android:verticalSpacing="@dimen/element_spacing_xsmall"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/name"
app:layout_constraintTop_toBottomOf="@+id/mediaLabel"
tools:visibility="visible">
<!-- Child views will be inflated if media preview enabled in ViewHolder -->
<!--<include layout="@layout/layout_card_media_preview"/>-->
</org.mariotaku.twidere.view.CardMediaContainer>
<org.mariotaku.twidere.view.ColorLabelLinearLayout
android:id="@+id/quotedView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/element_spacing_small"
android:background="?selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
android:paddingBottom="@dimen/element_spacing_small"
android:paddingEnd="@dimen/element_spacing_small"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_small"
android:paddingStart="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_small"
app:ignorePadding="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/name"
app:layout_constraintTop_toBottomOf="@+id/mediaPreview">
<org.mariotaku.twidere.view.NameView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginEnd="@dimen/element_spacing_small"
android:layout_marginRight="@dimen/element_spacing_small"
android:layout_toLeftOf="@+id/time"
android:layout_toStartOf="@+id/time"
android:ellipsize="end"
android:maxLines="1"
app:tltvPrimaryTextAppearance="?android:textAppearanceSmall"
app:tltvPrimaryTextColor="?android:textColorPrimary"
app:tltvPrimaryTextStyle="bold"
app:tltvSecondaryTextAppearance="?android:textAppearanceSmall"
app:tltvSecondaryTextColor="?android:textColorSecondary"
tools:tltvPrimaryText="Name"
tools:tltvSecondaryText="\@screenname"/>
<org.mariotaku.twidere.view.ShortTimeView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/name"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:textAppearance="?android:textAppearanceSmall"
tools:text="42 mins ago"
tools:textSize="@dimen/text_size_extra_small"/>
<org.mariotaku.twidere.view.TimelineContentTextView
android:id="@+id/summary"
android:id="@+id/quotedName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/name"
android:layout_alignStart="@+id/name"
android:layout_below="@+id/name"
android:paddingTop="@dimen/element_spacing_small"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
android:visibility="visible"
tools:text="@string/sample_summary_text"
android:gravity="center_vertical|start"
android:paddingEnd="0dp"
android:paddingLeft="@dimen/element_spacing_small"
android:paddingRight="0dp"
android:paddingStart="@dimen/element_spacing_small"
android:visibility="gone"
app:tltvPrimaryTextColor="?android:textColorPrimary"
app:tltvPrimaryTextStyle="bold"
app:tltvSecondaryTextColor="?android:textColorSecondary"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.TimelineContentTextView
android:id="@+id/text"
android:id="@+id/quotedText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/name"
android:layout_alignStart="@+id/name"
android:layout_below="@+id/summary"
android:paddingBottom="@dimen/element_spacing_small"
android:paddingEnd="0dp"
android:paddingLeft="@dimen/element_spacing_small"
android:paddingRight="0dp"
android:paddingStart="@dimen/element_spacing_small"
android:paddingTop="@dimen/element_spacing_small"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
android:visibility="visible"
android:visibility="gone"
tools:text="@string/sample_status_text"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.DrawableTintTextView
android:id="@+id/mediaLabel"
android:id="@+id/quotedMediaLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignEnd="@+id/text"
android:layout_alignLeft="@+id/text"
android:layout_alignRight="@+id/text"
android:layout_alignStart="@+id/text"
android:layout_below="@+id/text"
android:layout_marginTop="@dimen/element_spacing_xsmall"
android:background="?selectableItemBackground"
android:drawableLeft="@drawable/ic_label_gallery"
android:drawableStart="@drawable/ic_label_gallery"
android:gravity="center_vertical"
android:minHeight="@dimen/element_size_small"
android:textAppearance="?android:textAppearanceSmall"
android:textStyle="bold"
app:drawableTint="?android:textColorSecondary"
tools:text="@string/label_media"/>
tools:text="@string/label_media"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.CardMediaContainer
android:id="@+id/mediaPreview"
android:id="@+id/quotedMediaPreview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignEnd="@+id/text"
android:layout_alignLeft="@+id/text"
android:layout_alignRight="@+id/text"
android:layout_alignStart="@+id/text"
android:layout_below="@+id/mediaLabel"
android:layout_marginTop="@dimen/element_spacing_xsmall"
android:horizontalSpacing="@dimen/element_spacing_xsmall"
android:verticalSpacing="@dimen/element_spacing_xsmall"
tools:visibility="gone">
tools:visibility="gone"/>
</org.mariotaku.twidere.view.ColorLabelLinearLayout>
<!-- Child views will be inflated if media preview enabled in ViewHolder -->
<!--<include layout="@layout/layout_card_media_preview"/>-->
</org.mariotaku.twidere.view.CardMediaContainer>
<org.mariotaku.twidere.view.LabeledImageButton
android:id="@+id/reply"
style="?borderlessButtonStyle"
android:layout_width="@dimen/button_size_content_card_action"
android:layout_height="@dimen/button_size_content_card_action"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginStart="@dimen/element_spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/action_reply"
android:drawablePadding="@dimen/element_spacing_small"
android:padding="@dimen/element_spacing_small"
android:scaleType="centerInside"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/name"
app:layout_constraintTop_toBottomOf="@+id/quotedView"
app:srcCompat="@drawable/ic_action_reply"
app:tint="?android:textColorSecondary"
tools:text="255"/>
<org.mariotaku.twidere.view.ColorLabelRelativeLayout
android:id="@+id/quotedView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/mediaPreview"
android:layout_marginTop="@dimen/element_spacing_small"
android:background="?selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:paddingBottom="@dimen/element_spacing_small"
android:paddingEnd="@dimen/element_spacing_small"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_small"
android:paddingStart="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_small"
android:visibility="gone"
app:ignorePadding="true"
tools:visibility="visible">
<org.mariotaku.twidere.view.LabeledImageButton
android:id="@+id/retweet"
style="?borderlessButtonStyle"
android:layout_width="@dimen/button_size_content_card_action"
android:layout_height="@dimen/button_size_content_card_action"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginStart="@dimen/element_spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/action_retweet"
android:drawablePadding="@dimen/element_spacing_small"
android:padding="@dimen/element_spacing_small"
android:scaleType="centerInside"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
app:layout_constraintStart_toEndOf="@+id/reply"
app:layout_constraintTop_toBottomOf="@+id/quotedView"
app:srcCompat="@drawable/ic_action_retweet"
app:tint="@color/btn_tint_retweet_stateful"
tools:text="255"/>
<org.mariotaku.twidere.view.NameView
android:id="@+id/quotedName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:gravity="center_vertical|start"
android:orientation="horizontal"
android:paddingEnd="0dp"
android:paddingLeft="@dimen/element_spacing_small"
android:paddingRight="0dp"
android:paddingStart="@dimen/element_spacing_small"
android:visibility="gone"
app:tltvPrimaryTextColor="?android:textColorPrimary"
app:tltvPrimaryTextStyle="bold"
app:tltvSecondaryTextColor="?android:textColorSecondary"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.TimelineContentTextView
android:id="@+id/quotedText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/quotedName"
android:paddingBottom="@dimen/element_spacing_small"
android:paddingEnd="0dp"
android:paddingLeft="@dimen/element_spacing_small"
android:paddingRight="0dp"
android:paddingStart="@dimen/element_spacing_small"
android:paddingTop="@dimen/element_spacing_small"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
android:visibility="gone"
tools:text="@string/sample_status_text"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.DrawableTintTextView
android:id="@+id/quotedMediaLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/quotedText"
android:layout_marginTop="@dimen/element_spacing_xsmall"
android:drawableLeft="@drawable/ic_label_gallery"
android:drawableStart="@drawable/ic_label_gallery"
android:gravity="center_vertical"
android:textAppearance="?android:textAppearanceSmall"
android:textStyle="bold"
app:drawableTint="?android:textColorSecondary"
tools:text="@string/label_media"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.CardMediaContainer
android:id="@+id/quotedMediaPreview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/quotedMediaLabel"
android:horizontalSpacing="@dimen/element_spacing_xsmall"
android:verticalSpacing="@dimen/element_spacing_xsmall"
tools:visibility="gone"/>
</org.mariotaku.twidere.view.ColorLabelRelativeLayout>
</RelativeLayout>
<Space
android:id="@+id/statusContentLowerSpace"
android:layout_width="match_parent"
android:layout_height="@dimen/element_spacing_normal"
android:layout_below="@+id/statusContent"
android:visibility="gone"/>
<LinearLayout
android:id="@+id/actionButtons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/statusContent"
android:layout_alignStart="@+id/statusContent"
android:layout_below="@+id/statusContentLowerSpace"
android:layout_toLeftOf="@+id/itemMenu"
android:layout_toStartOf="@+id/itemMenu"
android:clipChildren="false"
android:gravity="center_vertical|start"
android:orientation="horizontal"
tools:visibility="visible">
<org.mariotaku.twidere.view.LabeledImageButton
android:id="@+id/reply"
style="?borderlessButtonStyle"
android:layout_width="@dimen/button_size_content_card_action"
android:layout_height="@dimen/button_size_content_card_action"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/action_reply"
android:drawablePadding="@dimen/element_spacing_small"
android:focusable="false"
android:gravity="center"
android:padding="@dimen/element_spacing_small"
android:scaleType="centerInside"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
app:srcCompat="@drawable/ic_action_reply"
app:tint="?android:textColorSecondary"
tools:text="255"/>
<org.mariotaku.twidere.view.LabeledImageButton
android:id="@+id/retweet"
style="?borderlessButtonStyle"
android:layout_width="@dimen/button_size_content_card_action"
android:layout_height="@dimen/button_size_content_card_action"
android:layout_marginLeft="@dimen/element_spacing_small"
android:layout_marginStart="@dimen/element_spacing_small"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/action_retweet"
android:drawablePadding="@dimen/element_spacing_small"
android:focusable="false"
android:gravity="center"
android:padding="@dimen/element_spacing_small"
android:scaleType="centerInside"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
app:srcCompat="@drawable/ic_action_retweet"
app:tint="@color/btn_tint_retweet_stateful"
tools:text="255"/>
<org.mariotaku.twidere.view.LabeledImageButton
android:id="@+id/favorite"
style="?borderlessButtonStyle"
android:layout_width="@dimen/button_size_content_card_action"
android:layout_height="@dimen/button_size_content_card_action"
android:layout_marginLeft="@dimen/element_spacing_small"
android:layout_marginStart="@dimen/element_spacing_small"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/action_like"
android:drawablePadding="@dimen/element_spacing_small"
android:focusable="false"
android:gravity="center"
android:padding="@dimen/element_spacing_small"
android:scaleType="centerInside"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
app:srcCompat="@drawable/ic_action_heart"
app:tint="@color/btn_tint_like_stateful"
tools:text="255"/>
</LinearLayout>
<org.mariotaku.twidere.view.LabeledImageButton
android:id="@+id/favorite"
style="?borderlessButtonStyle"
android:layout_width="@dimen/button_size_content_card_action"
android:layout_height="@dimen/button_size_content_card_action"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginStart="@dimen/element_spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/action_like"
android:drawablePadding="@dimen/element_spacing_small"
android:padding="@dimen/element_spacing_small"
android:scaleType="centerInside"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
app:layout_constraintStart_toEndOf="@+id/retweet"
app:layout_constraintTop_toBottomOf="@+id/quotedView"
app:srcCompat="@drawable/ic_action_heart"
app:tint="@color/btn_tint_like_stateful"
tools:text="255"/>
<android.support.v7.widget.AppCompatImageButton
android:id="@+id/itemMenu"
style="?cardActionButtonStyle"
style="?borderlessButtonStyle"
android:layout_width="@dimen/button_size_content_card_action"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/actionButtons"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignTop="@+id/actionButtons"
android:layout_height="@dimen/button_size_content_card_action"
android:layout_marginEnd="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_normal"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/action_more_actions"
android:focusable="false"
android:padding="@dimen/element_spacing_small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/quotedView"
app:srcCompat="@drawable/ic_action_more_horizontal"
app:tint="?android:textColorSecondary"
tools:visibility="visible"/>
app:tint="?android:textColorSecondary"/>
</org.mariotaku.twidere.view.ColorLabelRelativeLayout>
</org.mariotaku.twidere.view.ColorLabelConstraintLayout>