Merge pull request #4008 from vector-im/feature/fga/small_timeline_optimisation
Feature/fga/small timeline optimisation
This commit is contained in:
commit
b5f7351564
@ -239,7 +239,7 @@ data class Event(
|
|||||||
|
|
||||||
fun Event.isTextMessage(): Boolean {
|
fun Event.isTextMessage(): Boolean {
|
||||||
return getClearType() == EventType.MESSAGE
|
return getClearType() == EventType.MESSAGE
|
||||||
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) {
|
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
|
||||||
MessageType.MSGTYPE_TEXT,
|
MessageType.MSGTYPE_TEXT,
|
||||||
MessageType.MSGTYPE_EMOTE,
|
MessageType.MSGTYPE_EMOTE,
|
||||||
MessageType.MSGTYPE_NOTICE -> true
|
MessageType.MSGTYPE_NOTICE -> true
|
||||||
@ -249,7 +249,7 @@ fun Event.isTextMessage(): Boolean {
|
|||||||
|
|
||||||
fun Event.isImageMessage(): Boolean {
|
fun Event.isImageMessage(): Boolean {
|
||||||
return getClearType() == EventType.MESSAGE
|
return getClearType() == EventType.MESSAGE
|
||||||
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) {
|
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
|
||||||
MessageType.MSGTYPE_IMAGE -> true
|
MessageType.MSGTYPE_IMAGE -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
@ -257,7 +257,7 @@ fun Event.isImageMessage(): Boolean {
|
|||||||
|
|
||||||
fun Event.isVideoMessage(): Boolean {
|
fun Event.isVideoMessage(): Boolean {
|
||||||
return getClearType() == EventType.MESSAGE
|
return getClearType() == EventType.MESSAGE
|
||||||
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) {
|
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
|
||||||
MessageType.MSGTYPE_VIDEO -> true
|
MessageType.MSGTYPE_VIDEO -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
@ -265,7 +265,7 @@ fun Event.isVideoMessage(): Boolean {
|
|||||||
|
|
||||||
fun Event.isAudioMessage(): Boolean {
|
fun Event.isAudioMessage(): Boolean {
|
||||||
return getClearType() == EventType.MESSAGE
|
return getClearType() == EventType.MESSAGE
|
||||||
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) {
|
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
|
||||||
MessageType.MSGTYPE_AUDIO -> true
|
MessageType.MSGTYPE_AUDIO -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
@ -273,7 +273,7 @@ fun Event.isAudioMessage(): Boolean {
|
|||||||
|
|
||||||
fun Event.isFileMessage(): Boolean {
|
fun Event.isFileMessage(): Boolean {
|
||||||
return getClearType() == EventType.MESSAGE
|
return getClearType() == EventType.MESSAGE
|
||||||
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) {
|
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
|
||||||
MessageType.MSGTYPE_FILE -> true
|
MessageType.MSGTYPE_FILE -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
@ -281,7 +281,7 @@ fun Event.isFileMessage(): Boolean {
|
|||||||
|
|
||||||
fun Event.isAttachmentMessage(): Boolean {
|
fun Event.isAttachmentMessage(): Boolean {
|
||||||
return getClearType() == EventType.MESSAGE
|
return getClearType() == EventType.MESSAGE
|
||||||
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) {
|
&& when (getClearContent()?.get(MessageContent.MSG_TYPE_JSON_KEY)) {
|
||||||
MessageType.MSGTYPE_IMAGE,
|
MessageType.MSGTYPE_IMAGE,
|
||||||
MessageType.MSGTYPE_AUDIO,
|
MessageType.MSGTYPE_AUDIO,
|
||||||
MessageType.MSGTYPE_VIDEO,
|
MessageType.MSGTYPE_VIDEO,
|
||||||
|
@ -28,7 +28,7 @@ data class MessageAudioContent(
|
|||||||
/**
|
/**
|
||||||
* Required. Must be 'm.audio'.
|
* Required. Must be 'm.audio'.
|
||||||
*/
|
*/
|
||||||
@Json(name = "msgtype") override val msgType: String,
|
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required. A description of the audio e.g. 'Bee Gees - Stayin' Alive', or some kind of content description for accessibility e.g. 'audio attachment'.
|
* Required. A description of the audio e.g. 'Bee Gees - Stayin' Alive', or some kind of content description for accessibility e.g. 'audio attachment'.
|
||||||
|
@ -20,6 +20,11 @@ import org.matrix.android.sdk.api.session.events.model.Content
|
|||||||
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
||||||
|
|
||||||
interface MessageContent {
|
interface MessageContent {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val MSG_TYPE_JSON_KEY = "msgtype"
|
||||||
|
}
|
||||||
|
|
||||||
val msgType: String
|
val msgType: String
|
||||||
val body: String
|
val body: String
|
||||||
val relatesTo: RelationDefaultContent?
|
val relatesTo: RelationDefaultContent?
|
||||||
|
@ -23,7 +23,7 @@ import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultCon
|
|||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class MessageDefaultContent(
|
data class MessageDefaultContent(
|
||||||
@Json(name = "msgtype") override val msgType: String,
|
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||||
@Json(name = "body") override val body: String,
|
@Json(name = "body") override val body: String,
|
||||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||||
|
@ -26,7 +26,7 @@ data class MessageEmoteContent(
|
|||||||
/**
|
/**
|
||||||
* Required. Must be 'm.emote'.
|
* Required. Must be 'm.emote'.
|
||||||
*/
|
*/
|
||||||
@Json(name = "msgtype") override val msgType: String,
|
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required. The emote action to perform.
|
* Required. The emote action to perform.
|
||||||
|
@ -28,7 +28,7 @@ data class MessageFileContent(
|
|||||||
/**
|
/**
|
||||||
* Required. Must be 'm.file'.
|
* Required. Must be 'm.file'.
|
||||||
*/
|
*/
|
||||||
@Json(name = "msgtype") override val msgType: String,
|
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required. A human-readable description of the file. This is recommended to be the filename of the original upload.
|
* Required. A human-readable description of the file. This is recommended to be the filename of the original upload.
|
||||||
|
@ -27,7 +27,7 @@ data class MessageImageContent(
|
|||||||
/**
|
/**
|
||||||
* Required. Must be 'm.image'.
|
* Required. Must be 'm.image'.
|
||||||
*/
|
*/
|
||||||
@Json(name = "msgtype") override val msgType: String,
|
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required. A textual representation of the image. This could be the alt text of the image, the filename of the image,
|
* Required. A textual representation of the image. This could be the alt text of the image, the filename of the image,
|
||||||
|
@ -26,7 +26,7 @@ data class MessageLocationContent(
|
|||||||
/**
|
/**
|
||||||
* Required. Must be 'm.location'.
|
* Required. Must be 'm.location'.
|
||||||
*/
|
*/
|
||||||
@Json(name = "msgtype") override val msgType: String,
|
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required. A description of the location e.g. 'Big Ben, London, UK', or some kind
|
* Required. A description of the location e.g. 'Big Ben, London, UK', or some kind
|
||||||
|
@ -26,7 +26,7 @@ data class MessageNoticeContent(
|
|||||||
/**
|
/**
|
||||||
* Required. Must be 'm.notice'.
|
* Required. Must be 'm.notice'.
|
||||||
*/
|
*/
|
||||||
@Json(name = "msgtype") override val msgType: String,
|
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required. The notice text to send.
|
* Required. The notice text to send.
|
||||||
|
@ -30,7 +30,7 @@ const val OPTION_TYPE_BUTTONS = "org.matrix.buttons"
|
|||||||
*/
|
*/
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class MessageOptionsContent(
|
data class MessageOptionsContent(
|
||||||
@Json(name = "msgtype") override val msgType: String = MessageType.MSGTYPE_OPTIONS,
|
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String = MessageType.MSGTYPE_OPTIONS,
|
||||||
@Json(name = "type") val optionType: String? = null,
|
@Json(name = "type") val optionType: String? = null,
|
||||||
@Json(name = "body") override val body: String,
|
@Json(name = "body") override val body: String,
|
||||||
@Json(name = "label") val label: String?,
|
@Json(name = "label") val label: String?,
|
||||||
|
@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultCon
|
|||||||
*/
|
*/
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class MessagePollResponseContent(
|
data class MessagePollResponseContent(
|
||||||
@Json(name = "msgtype") override val msgType: String = MessageType.MSGTYPE_RESPONSE,
|
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String = MessageType.MSGTYPE_RESPONSE,
|
||||||
@Json(name = "body") override val body: String,
|
@Json(name = "body") override val body: String,
|
||||||
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
@Json(name = "m.relates_to") override val relatesTo: RelationDefaultContent? = null,
|
||||||
@Json(name = "m.new_content") override val newContent: Content? = null
|
@Json(name = "m.new_content") override val newContent: Content? = null
|
||||||
|
@ -26,7 +26,7 @@ data class MessageTextContent(
|
|||||||
/**
|
/**
|
||||||
* Required. Must be 'm.text'.
|
* Required. Must be 'm.text'.
|
||||||
*/
|
*/
|
||||||
@Json(name = "msgtype") override val msgType: String,
|
@Json(name = MessageContent.MSG_TYPE_JSON_KEY) override val msgType: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required. The body of the message.
|
* Required. The body of the message.
|
||||||
|
@ -24,7 +24,7 @@ import org.matrix.android.sdk.internal.crypto.verification.VerificationInfoReque
|
|||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class MessageVerificationRequestContent(
|
data class MessageVerificationRequestContent(
|
||||||
@Json(name = "msgtype") override val msgType: String = MessageType.MSGTYPE_VERIFICATION_REQUEST,
|
@Json(name = MessageContent.MSG_TYPE_JSON_KEY)override val msgType: String = MessageType.MSGTYPE_VERIFICATION_REQUEST,
|
||||||
@Json(name = "body") override val body: String,
|
@Json(name = "body") override val body: String,
|
||||||
@Json(name = "from_device") override val fromDevice: String?,
|
@Json(name = "from_device") override val fromDevice: String?,
|
||||||
@Json(name = "methods") override val methods: List<String>,
|
@Json(name = "methods") override val methods: List<String>,
|
||||||
|
@ -27,7 +27,7 @@ data class MessageVideoContent(
|
|||||||
/**
|
/**
|
||||||
* Required. Must be 'm.video'.
|
* Required. Must be 'm.video'.
|
||||||
*/
|
*/
|
||||||
@Json(name = "msgtype") override val msgType: String,
|
@Json(name = MessageContent.MSG_TYPE_JSON_KEY)override val msgType: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required. A description of the video e.g. 'Gangnam style', or some kind of content description for accessibility e.g. 'video attachment'.
|
* Required. A description of the video e.g. 'Gangnam style', or some kind of content description for accessibility e.g. 'video attachment'.
|
||||||
|
@ -15,27 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package im.vector.app.features.reactions.widget
|
package im.vector.app.features.reactions.widget
|
||||||
|
|
||||||
import android.animation.Animator
|
|
||||||
import android.animation.AnimatorListenerAdapter
|
|
||||||
import android.animation.AnimatorSet
|
|
||||||
import android.animation.ObjectAnimator
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.TypedArray
|
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import android.view.Gravity
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.animation.AccelerateDecelerateInterpolator
|
import android.widget.LinearLayout
|
||||||
import android.view.animation.DecelerateInterpolator
|
|
||||||
import android.view.animation.OvershootInterpolator
|
|
||||||
import android.widget.ImageView
|
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import androidx.annotation.ColorRes
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.withStyledAttributes
|
import androidx.core.content.withStyledAttributes
|
||||||
import im.vector.app.EmojiCompatWrapper
|
import im.vector.app.EmojiCompatWrapper
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.HasScreenInjector
|
import im.vector.app.core.di.HasScreenInjector
|
||||||
|
import im.vector.app.core.utils.DimensionConverter
|
||||||
import im.vector.app.core.utils.TextUtils
|
import im.vector.app.core.utils.TextUtils
|
||||||
import im.vector.app.databinding.ReactionButtonBinding
|
import im.vector.app.databinding.ReactionButtonBinding
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -47,7 +38,7 @@ import javax.inject.Inject
|
|||||||
class ReactionButton @JvmOverloads constructor(context: Context,
|
class ReactionButton @JvmOverloads constructor(context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = 0)
|
defStyleAttr: Int = 0)
|
||||||
: ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener, View.OnLongClickListener {
|
: LinearLayout(context, attrs, defStyleAttr), View.OnClickListener, View.OnLongClickListener {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (context is HasScreenInjector) {
|
if (context is HasScreenInjector) {
|
||||||
@ -55,21 +46,11 @@ class ReactionButton @JvmOverloads constructor(context: Context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val DECCELERATE_INTERPOLATOR = DecelerateInterpolator()
|
|
||||||
private val ACCELERATE_DECELERATE_INTERPOLATOR = AccelerateDecelerateInterpolator()
|
|
||||||
private val OVERSHOOT_INTERPOLATOR = OvershootInterpolator(4f)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject lateinit var emojiCompatWrapper: EmojiCompatWrapper
|
@Inject lateinit var emojiCompatWrapper: EmojiCompatWrapper
|
||||||
|
|
||||||
private val views: ReactionButtonBinding
|
private val views: ReactionButtonBinding
|
||||||
|
|
||||||
var reactedListener: ReactedListener? = null
|
var reactedListener: ReactedListener? = null
|
||||||
private var dotPrimaryColor: Int = 0
|
|
||||||
private var dotSecondaryColor: Int = 0
|
|
||||||
private var circleStartColor: Int = 0
|
|
||||||
private var circleEndColor: Int = 0
|
|
||||||
|
|
||||||
var reactionCount = 11
|
var reactionCount = 11
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -85,50 +66,24 @@ class ReactionButton @JvmOverloads constructor(context: Context,
|
|||||||
views.reactionText.text = emojiSpanned
|
views.reactionText.text = emojiSpanned
|
||||||
}
|
}
|
||||||
|
|
||||||
private var animationScaleFactor: Float = 0.toFloat()
|
|
||||||
|
|
||||||
private var isChecked: Boolean = false
|
private var isChecked: Boolean = false
|
||||||
|
|
||||||
private var animatorSet: AnimatorSet? = null
|
|
||||||
|
|
||||||
private var onDrawable: Drawable? = null
|
private var onDrawable: Drawable? = null
|
||||||
private var offDrawable: Drawable? = null
|
private var offDrawable: Drawable? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
inflate(context, R.layout.reaction_button, this)
|
inflate(context, R.layout.reaction_button, this)
|
||||||
|
orientation = HORIZONTAL
|
||||||
|
minimumHeight = DimensionConverter(context.resources).dpToPx(30)
|
||||||
|
gravity = Gravity.CENTER
|
||||||
views = ReactionButtonBinding.bind(this)
|
views = ReactionButtonBinding.bind(this)
|
||||||
views.reactionCount.text = TextUtils.formatCountToShortDecimal(reactionCount)
|
views.reactionCount.text = TextUtils.formatCountToShortDecimal(reactionCount)
|
||||||
|
|
||||||
// emojiView?.typeface = this.emojiTypeFace ?: Typeface.DEFAULT
|
|
||||||
context.withStyledAttributes(attrs, R.styleable.ReactionButton, defStyleAttr) {
|
context.withStyledAttributes(attrs, R.styleable.ReactionButton, defStyleAttr) {
|
||||||
onDrawable = ContextCompat.getDrawable(context, R.drawable.reaction_rounded_rect_shape)
|
onDrawable = ContextCompat.getDrawable(context, R.drawable.reaction_rounded_rect_shape)
|
||||||
offDrawable = ContextCompat.getDrawable(context, R.drawable.reaction_rounded_rect_shape_off)
|
offDrawable = ContextCompat.getDrawable(context, R.drawable.reaction_rounded_rect_shape_off)
|
||||||
|
|
||||||
circleStartColor = getColor(R.styleable.ReactionButton_circle_start_color, 0)
|
|
||||||
|
|
||||||
if (circleStartColor != 0) {
|
|
||||||
views.circle.startColor = circleStartColor
|
|
||||||
}
|
|
||||||
|
|
||||||
circleEndColor = getColor(R.styleable.ReactionButton_circle_end_color, 0)
|
|
||||||
|
|
||||||
if (circleEndColor != 0) {
|
|
||||||
views.circle.endColor = circleEndColor
|
|
||||||
}
|
|
||||||
|
|
||||||
dotPrimaryColor = getColor(R.styleable.ReactionButton_dots_primary_color, 0)
|
|
||||||
dotSecondaryColor = getColor(R.styleable.ReactionButton_dots_secondary_color, 0)
|
|
||||||
|
|
||||||
if (dotPrimaryColor != 0 && dotSecondaryColor != 0) {
|
|
||||||
views.dots.setColors(dotPrimaryColor, dotSecondaryColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
getString(R.styleable.ReactionButton_emoji)?.let {
|
getString(R.styleable.ReactionButton_emoji)?.let {
|
||||||
reactionString = it
|
reactionString = it
|
||||||
}
|
}
|
||||||
|
|
||||||
reactionCount = getInt(R.styleable.ReactionButton_reaction_count, 0)
|
reactionCount = getInt(R.styleable.ReactionButton_reaction_count, 0)
|
||||||
|
|
||||||
val status = getBoolean(R.styleable.ReactionButton_toggled, false)
|
val status = getBoolean(R.styleable.ReactionButton_toggled, false)
|
||||||
setChecked(status)
|
setChecked(status)
|
||||||
}
|
}
|
||||||
@ -137,12 +92,6 @@ class ReactionButton @JvmOverloads constructor(context: Context,
|
|||||||
setOnLongClickListener(this)
|
setOnLongClickListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDrawableFromResource(array: TypedArray, styleableIndexId: Int): Drawable? {
|
|
||||||
val id = array.getResourceId(styleableIndexId, -1)
|
|
||||||
|
|
||||||
return if (-1 != id) ContextCompat.getDrawable(context, id) else null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This triggers the entire functionality of the button such as icon changes,
|
* This triggers the entire functionality of the button such as icon changes,
|
||||||
* animations, listeners etc.
|
* animations, listeners etc.
|
||||||
@ -153,164 +102,25 @@ class ReactionButton @JvmOverloads constructor(context: Context,
|
|||||||
if (!isEnabled) {
|
if (!isEnabled) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
isChecked = !isChecked
|
isChecked = !isChecked
|
||||||
|
|
||||||
// icon!!.setImageDrawable(if (isChecked) likeDrawable else unLikeDrawable)
|
// icon!!.setImageDrawable(if (isChecked) likeDrawable else unLikeDrawable)
|
||||||
background = if (isChecked) onDrawable else offDrawable
|
background = if (isChecked) onDrawable else offDrawable
|
||||||
|
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
reactedListener?.onReacted(this)
|
reactedListener?.onReacted(this)
|
||||||
} else {
|
|
||||||
reactedListener?.onUnReacted(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (animatorSet != null) {
|
|
||||||
animatorSet!!.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isChecked) {
|
|
||||||
views.reactionText.animate().cancel()
|
views.reactionText.animate().cancel()
|
||||||
views.reactionText.scaleX = 0f
|
views.reactionText.scaleX = 0f
|
||||||
views.reactionText.scaleY = 0f
|
views.reactionText.scaleY = 0f
|
||||||
|
} else {
|
||||||
views.circle.innerCircleRadiusProgress = 0f
|
reactedListener?.onUnReacted(this)
|
||||||
views.circle.outerCircleRadiusProgress = 0f
|
|
||||||
views.dots.currentProgress = 0f
|
|
||||||
|
|
||||||
animatorSet = AnimatorSet()
|
|
||||||
|
|
||||||
val outerCircleAnimator = ObjectAnimator.ofFloat(views.circle, CircleView.OUTER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f)
|
|
||||||
outerCircleAnimator.duration = 250
|
|
||||||
outerCircleAnimator.interpolator = DECCELERATE_INTERPOLATOR
|
|
||||||
|
|
||||||
val innerCircleAnimator = ObjectAnimator.ofFloat(views.circle, CircleView.INNER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f)
|
|
||||||
innerCircleAnimator.duration = 200
|
|
||||||
innerCircleAnimator.startDelay = 200
|
|
||||||
innerCircleAnimator.interpolator = DECCELERATE_INTERPOLATOR
|
|
||||||
|
|
||||||
val starScaleYAnimator = ObjectAnimator.ofFloat(views.reactionText, ImageView.SCALE_Y, 0.2f, 1f)
|
|
||||||
starScaleYAnimator.duration = 350
|
|
||||||
starScaleYAnimator.startDelay = 250
|
|
||||||
starScaleYAnimator.interpolator = OVERSHOOT_INTERPOLATOR
|
|
||||||
|
|
||||||
val starScaleXAnimator = ObjectAnimator.ofFloat(views.reactionText, ImageView.SCALE_X, 0.2f, 1f)
|
|
||||||
starScaleXAnimator.duration = 350
|
|
||||||
starScaleXAnimator.startDelay = 250
|
|
||||||
starScaleXAnimator.interpolator = OVERSHOOT_INTERPOLATOR
|
|
||||||
|
|
||||||
val dotsAnimator = ObjectAnimator.ofFloat(views.dots, DotsView.DOTS_PROGRESS, 0f, 1f)
|
|
||||||
// .ofFloat<DotsView>(views.dots, DotsView.DOTS_PROGRESS, 0, 1f)
|
|
||||||
dotsAnimator.duration = 900
|
|
||||||
dotsAnimator.startDelay = 50
|
|
||||||
dotsAnimator.interpolator = ACCELERATE_DECELERATE_INTERPOLATOR
|
|
||||||
|
|
||||||
animatorSet!!.playTogether(
|
|
||||||
outerCircleAnimator,
|
|
||||||
innerCircleAnimator,
|
|
||||||
starScaleYAnimator,
|
|
||||||
starScaleXAnimator,
|
|
||||||
dotsAnimator
|
|
||||||
)
|
|
||||||
|
|
||||||
animatorSet!!.addListener(object : AnimatorListenerAdapter() {
|
|
||||||
override fun onAnimationCancel(animation: Animator) {
|
|
||||||
views.circle.innerCircleRadiusProgress = 0f
|
|
||||||
views.circle.outerCircleRadiusProgress = 0f
|
|
||||||
views.dots.currentProgress = 0f
|
|
||||||
views.reactionText.scaleX = 1f
|
|
||||||
views.reactionText.scaleY = 1f
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAnimationEnd(animation: Animator) {
|
|
||||||
// if (animationEndListener != null) {
|
|
||||||
// // animationEndListener!!.onAnimationEnd(this@ReactionButton)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
animatorSet!!.start()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to trigger the scale animation that takes places on the
|
|
||||||
* icon when the button is touched.
|
|
||||||
*
|
|
||||||
* @param event
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
// override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
||||||
// if (!isEnabled)
|
|
||||||
// return true
|
|
||||||
//
|
|
||||||
// when (event.action) {
|
|
||||||
// MotionEvent.ACTION_DOWN ->
|
|
||||||
// /*
|
|
||||||
// Commented out this line and moved the animation effect to the action up event due to
|
|
||||||
// conflicts that were occurring when library is used in sliding type views.
|
|
||||||
//
|
|
||||||
// icon.animate().scaleX(0.7f).scaleY(0.7f).setDuration(150).setInterpolator(DECCELERATE_INTERPOLATOR);
|
|
||||||
// */
|
|
||||||
// isPressed = true
|
|
||||||
//
|
|
||||||
// MotionEvent.ACTION_MOVE -> {
|
|
||||||
// val x = event.x
|
|
||||||
// val y = event.y
|
|
||||||
// val isInside = x > 0 && x < width && y > 0 && y < height
|
|
||||||
// if (isPressed != isInside) {
|
|
||||||
// isPressed = isInside
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// MotionEvent.ACTION_UP -> {
|
|
||||||
// views.reactionText!!.animate().scaleX(0.7f).scaleY(0.7f).setDuration(150).interpolator = DECCELERATE_INTERPOLATOR
|
|
||||||
// views.reactionText!!.animate().scaleX(1f).scaleY(1f).interpolator = DECCELERATE_INTERPOLATOR
|
|
||||||
// if (isPressed) {
|
|
||||||
// performClick()
|
|
||||||
// isPressed = false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// MotionEvent.ACTION_CANCEL -> isPressed = false
|
|
||||||
// }
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
|
|
||||||
override fun onLongClick(v: View?): Boolean {
|
override fun onLongClick(v: View?): Boolean {
|
||||||
reactedListener?.onLongClick(this)
|
reactedListener?.onLongClick(this)
|
||||||
return reactedListener != null
|
return reactedListener != null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This set sets the colours that are used for the little dots
|
|
||||||
* that will be exploding once the like button is clicked.
|
|
||||||
*
|
|
||||||
* @param primaryColor
|
|
||||||
* @param secondaryColor
|
|
||||||
*/
|
|
||||||
fun setExplodingDotColorsRes(@ColorRes primaryColor: Int, @ColorRes secondaryColor: Int) {
|
|
||||||
views.dots.setColors(ContextCompat.getColor(context, primaryColor), ContextCompat.getColor(context, secondaryColor))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setExplodingDotColorsInt(@ColorInt primaryColor: Int, @ColorInt secondaryColor: Int) {
|
|
||||||
views.dots.setColors(primaryColor, secondaryColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setCircleStartColorRes(@ColorRes circleStartColor: Int) {
|
|
||||||
this.circleStartColor = ContextCompat.getColor(context, circleStartColor)
|
|
||||||
views.circle.startColor = this.circleStartColor
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setCircleStartColorInt(@ColorInt circleStartColor: Int) {
|
|
||||||
this.circleStartColor = circleStartColor
|
|
||||||
views.circle.startColor = circleStartColor
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setCircleEndColorRes(@ColorRes circleEndColor: Int) {
|
|
||||||
this.circleEndColor = ContextCompat.getColor(context, circleEndColor)
|
|
||||||
views.circle.endColor = this.circleEndColor
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the initial state of the button to liked
|
* Sets the initial state of the button to liked
|
||||||
* or unliked.
|
* or unliked.
|
||||||
@ -327,13 +137,6 @@ class ReactionButton @JvmOverloads constructor(context: Context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the factor by which the dots should be sized.
|
|
||||||
*/
|
|
||||||
fun setAnimationScaleFactor(animationScaleFactor: Float) {
|
|
||||||
this.animationScaleFactor = animationScaleFactor
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ReactedListener {
|
interface ReactedListener {
|
||||||
fun onReacted(reactionButton: ReactionButton)
|
fun onReacted(reactionButton: ReactionButton)
|
||||||
fun onUnReacted(reactionButton: ReactionButton)
|
fun onUnReacted(reactionButton: ReactionButton)
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
android:background="@drawable/reaction_rounded_rect_shape"
|
android:background="@drawable/reaction_rounded_rect_shape"
|
||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
android:minWidth="44dp"
|
android:minWidth="44dp"
|
||||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
android:gravity="center"
|
||||||
|
tools:parentTag="android.widget.LinearLayout">
|
||||||
|
|
||||||
<!--<View-->
|
<!--<View-->
|
||||||
<!--android:id="@+id/reactionSelector"-->
|
<!--android:id="@+id/reactionSelector"-->
|
||||||
@ -15,25 +16,6 @@
|
|||||||
<!--android:layout_height="match_parent"-->
|
<!--android:layout_height="match_parent"-->
|
||||||
<!--android:background="@drawable/rounded_rect_shape" />-->
|
<!--android:background="@drawable/rounded_rect_shape" />-->
|
||||||
|
|
||||||
<im.vector.app.features.reactions.widget.DotsView
|
|
||||||
android:id="@+id/dots"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:clipChildren="false"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/reactionText"
|
|
||||||
app:layout_constraintEnd_toEndOf="@+id/reactionText"
|
|
||||||
app:layout_constraintStart_toStartOf="@+id/reactionText"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/reactionText" />
|
|
||||||
|
|
||||||
<im.vector.app.features.reactions.widget.CircleView
|
|
||||||
android:id="@+id/circle"
|
|
||||||
android:layout_width="14dp"
|
|
||||||
android:layout_height="14dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/reactionText"
|
|
||||||
app:layout_constraintEnd_toEndOf="@+id/reactionText"
|
|
||||||
app:layout_constraintStart_toStartOf="@+id/reactionText"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/reactionText" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/reactionText"
|
android:id="@+id/reactionText"
|
||||||
style="@style/Widget.Vector.TextView.Caption"
|
style="@style/Widget.Vector.TextView.Caption"
|
||||||
@ -46,11 +28,6 @@
|
|||||||
android:minWidth="20dp"
|
android:minWidth="20dp"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textColor="@color/emoji_color"
|
android:textColor="@color/emoji_color"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/reactionCount"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:text="* Party Parrot Again * 👀" />
|
tools:text="* Party Parrot Again * 👀" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -67,10 +44,6 @@
|
|||||||
app:autoSizeMaxTextSize="14sp"
|
app:autoSizeMaxTextSize="14sp"
|
||||||
app:autoSizeMinTextSize="8sp"
|
app:autoSizeMinTextSize="8sp"
|
||||||
app:autoSizeTextType="uniform"
|
app:autoSizeTextType="uniform"
|
||||||
app:layout_constraintBaseline_toBaselineOf="@id/reactionText"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/reactionText"
|
|
||||||
tools:text="13450" />
|
tools:text="13450" />
|
||||||
|
|
||||||
</merge>
|
</merge>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user