mirror of
https://github.com/nextcloud/talk-android.git
synced 2024-11-26 23:25:20 +03:00
Merge pull request #1313 from nextcloud/swipeToReply
Swipe-right to reply
This commit is contained in:
commit
3e17bf31ff
4 changed files with 414 additions and 57 deletions
|
@ -58,6 +58,7 @@ import androidx.appcompat.view.ContextThemeWrapper
|
|||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
||||
import androidx.emoji.text.EmojiCompat
|
||||
import androidx.emoji.widget.EmojiTextView
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.work.Data
|
||||
|
@ -107,6 +108,8 @@ import com.nextcloud.talk.models.json.generic.GenericOverall
|
|||
import com.nextcloud.talk.models.json.mention.Mention
|
||||
import com.nextcloud.talk.presenters.MentionAutocompletePresenter
|
||||
import com.nextcloud.talk.ui.dialog.AttachmentDialog
|
||||
import com.nextcloud.talk.ui.recyclerview.MessageSwipeActions
|
||||
import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.ConductorRemapping
|
||||
import com.nextcloud.talk.utils.ConductorRemapping.remapChatController
|
||||
|
@ -448,6 +451,21 @@ class ChatController(args: Bundle) :
|
|||
adapter?.setDateHeadersFormatter { format(it) }
|
||||
adapter?.setOnMessageViewLongClickListener { view, message -> onMessageViewLongClick(view, message) }
|
||||
|
||||
if (context != null) {
|
||||
val messageSwipeController = MessageSwipeCallback(
|
||||
activity!!,
|
||||
object : MessageSwipeActions {
|
||||
override fun showReplyUI(position: Int) {
|
||||
val chatMessage = adapter?.items?.get(position)?.item as ChatMessage?
|
||||
replyToMessage(chatMessage, chatMessage?.jsonMessageId)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
val itemTouchHelper = ItemTouchHelper(messageSwipeController)
|
||||
itemTouchHelper.attachToRecyclerView(binding.messagesListView)
|
||||
}
|
||||
|
||||
layoutManager = binding.messagesListView.layoutManager as LinearLayoutManager?
|
||||
|
||||
binding.popupBubbleView.setRecyclerView(binding.messagesListView)
|
||||
|
@ -1357,10 +1375,8 @@ class ChatController(args: Bundle) :
|
|||
if (TextUtils.isEmpty(chatMessageList[i].systemMessage) &&
|
||||
TextUtils.isEmpty(chatMessageList[i + 1].systemMessage) &&
|
||||
chatMessageList[i + 1].actorId == chatMessageList[i].actorId &&
|
||||
countGroupedMessages < 4 && DateFormatter.isSameDay(
|
||||
chatMessageList[i].createdAt,
|
||||
chatMessageList[i + 1].createdAt
|
||||
)
|
||||
countGroupedMessages < 4 &&
|
||||
DateFormatter.isSameDay(chatMessageList[i].createdAt, chatMessageList[i + 1].createdAt)
|
||||
) {
|
||||
chatMessageList[i].isGrouped = true
|
||||
countGroupedMessages++
|
||||
|
@ -1624,58 +1640,7 @@ class ChatController(args: Bundle) :
|
|||
}
|
||||
R.id.action_reply_to_message -> {
|
||||
val chatMessage = message as ChatMessage?
|
||||
chatMessage?.let {
|
||||
binding.messageInputView.findViewById<ImageButton>(R.id.attachmentButton)?.visibility =
|
||||
View.GONE
|
||||
binding.messageInputView.findViewById<Space>(R.id.attachmentButtonSpace)?.visibility =
|
||||
View.GONE
|
||||
binding.messageInputView.findViewById<ImageButton>(R.id.cancelReplyButton)?.visibility =
|
||||
View.VISIBLE
|
||||
|
||||
val quotedMessage = binding
|
||||
.messageInputView
|
||||
.findViewById<EmojiTextView>(R.id.quotedMessage)
|
||||
|
||||
quotedMessage?.maxLines = 2
|
||||
quotedMessage?.ellipsize = TextUtils.TruncateAt.END
|
||||
quotedMessage?.text = it.text
|
||||
binding.messageInputView.findViewById<EmojiTextView>(R.id.quotedMessageAuthor)?.text =
|
||||
it.actorDisplayName ?: context!!.getText(R.string.nc_nick_guest)
|
||||
|
||||
conversationUser?.let { currentUser ->
|
||||
val quotedMessageImage = binding
|
||||
.messageInputView
|
||||
.findViewById<ImageView>(R.id.quotedMessageImage)
|
||||
chatMessage.imageUrl?.let { previewImageUrl ->
|
||||
quotedMessageImage?.visibility = View.VISIBLE
|
||||
|
||||
val px = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
96f,
|
||||
resources?.displayMetrics
|
||||
)
|
||||
|
||||
quotedMessageImage?.maxHeight = px.toInt()
|
||||
val layoutParams = quotedMessageImage?.layoutParams as FlexboxLayout.LayoutParams
|
||||
layoutParams.flexGrow = 0f
|
||||
quotedMessageImage.layoutParams = layoutParams
|
||||
quotedMessageImage.load(previewImageUrl) {
|
||||
addHeader("Authorization", credentials!!)
|
||||
}
|
||||
} ?: run {
|
||||
binding
|
||||
.messageInputView
|
||||
.findViewById<ImageView>(R.id.quotedMessageImage)
|
||||
?.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
val quotedChatMessageView = binding
|
||||
.messageInputView
|
||||
.findViewById<RelativeLayout>(R.id.quotedChatMessageView)
|
||||
quotedChatMessageView?.tag = message?.jsonMessageId
|
||||
quotedChatMessageView?.visibility = View.VISIBLE
|
||||
}
|
||||
replyToMessage(chatMessage, message?.jsonMessageId)
|
||||
true
|
||||
}
|
||||
R.id.action_reply_privately -> {
|
||||
|
@ -1820,6 +1785,61 @@ class ChatController(args: Bundle) :
|
|||
}
|
||||
}
|
||||
|
||||
private fun replyToMessage(chatMessage: ChatMessage?, jsonMessageId: Int?) {
|
||||
chatMessage?.let {
|
||||
binding.messageInputView.findViewById<ImageButton>(R.id.attachmentButton)?.visibility =
|
||||
View.GONE
|
||||
binding.messageInputView.findViewById<Space>(R.id.attachmentButtonSpace)?.visibility =
|
||||
View.GONE
|
||||
binding.messageInputView.findViewById<ImageButton>(R.id.cancelReplyButton)?.visibility =
|
||||
View.VISIBLE
|
||||
|
||||
val quotedMessage = binding
|
||||
.messageInputView
|
||||
.findViewById<EmojiTextView>(R.id.quotedMessage)
|
||||
|
||||
quotedMessage?.maxLines = 2
|
||||
quotedMessage?.ellipsize = TextUtils.TruncateAt.END
|
||||
quotedMessage?.text = it.text
|
||||
binding.messageInputView.findViewById<EmojiTextView>(R.id.quotedMessageAuthor)?.text =
|
||||
it.actorDisplayName ?: context!!.getText(R.string.nc_nick_guest)
|
||||
|
||||
conversationUser?.let { currentUser ->
|
||||
val quotedMessageImage = binding
|
||||
.messageInputView
|
||||
.findViewById<ImageView>(R.id.quotedMessageImage)
|
||||
chatMessage.imageUrl?.let { previewImageUrl ->
|
||||
quotedMessageImage?.visibility = View.VISIBLE
|
||||
|
||||
val px = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
96f,
|
||||
resources?.displayMetrics
|
||||
)
|
||||
|
||||
quotedMessageImage?.maxHeight = px.toInt()
|
||||
val layoutParams = quotedMessageImage?.layoutParams as FlexboxLayout.LayoutParams
|
||||
layoutParams.flexGrow = 0f
|
||||
quotedMessageImage.layoutParams = layoutParams
|
||||
quotedMessageImage.load(previewImageUrl) {
|
||||
addHeader("Authorization", credentials!!)
|
||||
}
|
||||
} ?: run {
|
||||
binding
|
||||
.messageInputView
|
||||
.findViewById<ImageView>(R.id.quotedMessageImage)
|
||||
?.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
val quotedChatMessageView = binding
|
||||
.messageInputView
|
||||
.findViewById<RelativeLayout>(R.id.quotedChatMessageView)
|
||||
quotedChatMessageView?.tag = jsonMessageId
|
||||
quotedChatMessageView?.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMessageAsDeleted(message: IMessage?) {
|
||||
val messageTemp = message as ChatMessage
|
||||
messageTemp.isDeleted = true
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Shain Singh
|
||||
* @author Andy Scherzinger
|
||||
* Copyright (C) 2021 Shain Singh <shainsingh89@gmail.com>
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Based on the MessageSwipeController by Shain Singh at:
|
||||
* https://github.com/shainsingh89/SwipeToReply/blob/master/app/src/main/java/com/shain/messenger/SwipeControllerActions.kt
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.ui.recyclerview
|
||||
|
||||
/**
|
||||
* Actions executed within a swipe gesture.
|
||||
*/
|
||||
interface MessageSwipeActions {
|
||||
|
||||
/**
|
||||
* Display reply message including the original, quoted message of/at [position].
|
||||
*/
|
||||
fun showReplyUI(position: Int)
|
||||
}
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Shain Singh
|
||||
* @author Andy Scherzinger
|
||||
* Copyright (C) 2021 Shain Singh <shainsingh89@gmail.com>
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Based on the MessageSwipeController by Shain Singh at:
|
||||
* https://github.com/shainsingh89/SwipeToReply/blob/master/app/src/main/java/com/shain/messenger/MessageSwipeController.kt
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.ui.recyclerview
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.Log
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_IDLE
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_SWIPE
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.RIGHT
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.adapters.messages.MagicIncomingTextMessageViewHolder
|
||||
import com.nextcloud.talk.adapters.messages.MagicOutcomingTextMessageViewHolder
|
||||
import com.nextcloud.talk.adapters.messages.MagicPreviewMessageViewHolder
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* Callback implementation for swipe-right-gesture on messages.
|
||||
*
|
||||
* @property context activity's context to load resources like drawables.
|
||||
* @property messageSwipeActions the actions to be executed upon swipe-right.
|
||||
* @constructor Creates as swipe-right callback for messages
|
||||
*/
|
||||
class MessageSwipeCallback(private val context: Context, private val messageSwipeActions: MessageSwipeActions) :
|
||||
ItemTouchHelper.Callback() {
|
||||
|
||||
private var density = DENSITY_DEFAULT
|
||||
|
||||
private lateinit var imageDrawable: Drawable
|
||||
private lateinit var shareRound: Drawable
|
||||
|
||||
private var currentItemViewHolder: RecyclerView.ViewHolder? = null
|
||||
private lateinit var view: View
|
||||
private var dX = 0f
|
||||
|
||||
private var replyButtonProgress: Float = NO_PROGRESS
|
||||
private var lastReplyButtonAnimationTime: Long = 0
|
||||
private var swipeBack = false
|
||||
private var isVibrate = false
|
||||
private var startTracking = false
|
||||
|
||||
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
|
||||
if (viewHolder is MagicPreviewMessageViewHolder ||
|
||||
viewHolder is MagicIncomingTextMessageViewHolder ||
|
||||
viewHolder is MagicOutcomingTextMessageViewHolder
|
||||
) {
|
||||
view = viewHolder.itemView
|
||||
imageDrawable = AppCompatResources.getDrawable(context, R.drawable.ic_reply)!!
|
||||
shareRound = AppCompatResources.getDrawable(context, R.drawable.round_bgnd)!!
|
||||
return makeMovementFlags(ACTION_STATE_IDLE, RIGHT)
|
||||
}
|
||||
|
||||
// disable swiping any other message type
|
||||
return NO_SWIPE_FLAG
|
||||
}
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
// unused atm
|
||||
}
|
||||
|
||||
override fun convertToAbsoluteDirection(flags: Int, layoutDirection: Int): Int {
|
||||
if (swipeBack) {
|
||||
swipeBack = false
|
||||
return 0
|
||||
}
|
||||
return super.convertToAbsoluteDirection(flags, layoutDirection)
|
||||
}
|
||||
|
||||
override fun onChildDraw(
|
||||
c: Canvas,
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
dX: Float,
|
||||
dY: Float,
|
||||
actionState: Int,
|
||||
isCurrentlyActive: Boolean
|
||||
) {
|
||||
|
||||
if (actionState == ACTION_STATE_SWIPE) {
|
||||
setTouchListener(recyclerView, viewHolder)
|
||||
}
|
||||
|
||||
if (view.translationX < convertToDp(SWIPE_LIMIT) || dX < this.dX) {
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
||||
this.dX = dX
|
||||
startTracking = true
|
||||
}
|
||||
currentItemViewHolder = viewHolder
|
||||
drawReplyButton(c)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private fun setTouchListener(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||
recyclerView.setOnTouchListener { _, event ->
|
||||
swipeBack = event.action == MotionEvent.ACTION_CANCEL || event.action == MotionEvent.ACTION_UP
|
||||
if (swipeBack) {
|
||||
if (abs(view.translationX) >= this@MessageSwipeCallback.convertToDp(REPLY_POINT)) {
|
||||
messageSwipeActions.showReplyUI(viewHolder.adapterPosition)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawReplyButton(canvas: Canvas) {
|
||||
if (currentItemViewHolder == null) {
|
||||
return
|
||||
}
|
||||
val translationX = view.translationX
|
||||
val newTime = System.currentTimeMillis()
|
||||
val dt = min(MIN_ANIMATION_TIME_IN_MILLIS, newTime - lastReplyButtonAnimationTime)
|
||||
lastReplyButtonAnimationTime = newTime
|
||||
val showing = translationX >= convertToDp(SHOW_REPLY_ICON_POINT)
|
||||
if (showing) {
|
||||
if (replyButtonProgress < FULL_PROGRESS) {
|
||||
replyButtonProgress += dt / PROGRESS_CALCULATION_TIME_BASE
|
||||
if (replyButtonProgress > FULL_PROGRESS) {
|
||||
replyButtonProgress = FULL_PROGRESS
|
||||
} else {
|
||||
view.invalidate()
|
||||
}
|
||||
}
|
||||
} else if (translationX <= NO_PROGRESS) {
|
||||
replyButtonProgress = NO_PROGRESS
|
||||
startTracking = false
|
||||
isVibrate = false
|
||||
} else {
|
||||
if (replyButtonProgress > NO_PROGRESS) {
|
||||
replyButtonProgress -= dt / PROGRESS_CALCULATION_TIME_BASE
|
||||
if (replyButtonProgress < PROGRESS_THRESHOLD) {
|
||||
replyButtonProgress = NO_PROGRESS
|
||||
} else {
|
||||
view.invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val alpha: Int
|
||||
val scale: Float
|
||||
if (showing) {
|
||||
scale = if (replyButtonProgress <= SCALE_PROGRESS_TOP_THRESHOLD) {
|
||||
SCALE_PROGRESS_MULTIPLIER * (replyButtonProgress / SCALE_PROGRESS_TOP_THRESHOLD)
|
||||
} else {
|
||||
SCALE_PROGRESS_MULTIPLIER -
|
||||
SCALE_PROGRESS_BOTTOM_THRESHOLD *
|
||||
((replyButtonProgress - SCALE_PROGRESS_TOP_THRESHOLD) / SCALE_PROGRESS_BOTTOM_THRESHOLD)
|
||||
}
|
||||
alpha = min(FULLY_OPAQUE, FULLY_OPAQUE * (replyButtonProgress / SCALE_PROGRESS_TOP_THRESHOLD)).toInt()
|
||||
} else {
|
||||
scale = replyButtonProgress
|
||||
alpha = min(FULLY_OPAQUE, FULLY_OPAQUE * replyButtonProgress).toInt()
|
||||
}
|
||||
|
||||
if (startTracking && !isVibrate && view.translationX >= convertToDp(REPLY_POINT)) {
|
||||
view.performHapticFeedback(
|
||||
HapticFeedbackConstants.KEYBOARD_TAP,
|
||||
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
|
||||
)
|
||||
isVibrate = true
|
||||
}
|
||||
|
||||
drawReplyIcon(alpha, scale, canvas)
|
||||
}
|
||||
|
||||
private fun drawReplyIcon(alpha: Int, scale: Float, canvas: Canvas) {
|
||||
val x: Int = if (view.translationX > convertToDp(SWIPE_LIMIT)) {
|
||||
convertToDp(SWIPE_LIMIT) / AXIS_BASE
|
||||
} else {
|
||||
(view.translationX / AXIS_BASE).toInt()
|
||||
}
|
||||
|
||||
val y = (view.top + view.measuredHeight / AXIS_BASE).toFloat()
|
||||
|
||||
shareRound.alpha = alpha
|
||||
imageDrawable.alpha = alpha
|
||||
|
||||
shareRound.colorFilter = PorterDuffColorFilter(
|
||||
ContextCompat.getColor(context, R.color.bg_message_list_incoming_bubble),
|
||||
PorterDuff.Mode.SRC_IN
|
||||
)
|
||||
imageDrawable.colorFilter = PorterDuffColorFilter(
|
||||
ContextCompat.getColor(context, R.color.high_emphasis_text),
|
||||
PorterDuff.Mode.SRC_IN
|
||||
)
|
||||
|
||||
shareRound.setBounds(
|
||||
(x - convertToDp(BACKGROUND_BOUNDS_PIXEL) * scale).toInt(),
|
||||
(y - convertToDp(BACKGROUND_BOUNDS_PIXEL) * scale).toInt(),
|
||||
(x + convertToDp(BACKGROUND_BOUNDS_PIXEL) * scale).toInt(),
|
||||
(y + convertToDp(BACKGROUND_BOUNDS_PIXEL) * scale).toInt()
|
||||
)
|
||||
shareRound.draw(canvas)
|
||||
|
||||
imageDrawable.setBounds(
|
||||
(x - convertToDp(ICON_BOUNDS_PIXEL_LEFT) * scale).toInt(),
|
||||
(y - convertToDp(ICON_BOUNDS_PIXEL_TOP) * scale).toInt(),
|
||||
(x + convertToDp(ICON_BOUNDS_PIXEL_RIGHT) * scale).toInt(),
|
||||
(y + convertToDp(ICON_BOUNDS_PIXEL_BOTTOM) * scale).toInt()
|
||||
)
|
||||
imageDrawable.draw(canvas)
|
||||
|
||||
shareRound.alpha = FULLY_OPAQUE_INT
|
||||
imageDrawable.alpha = FULLY_OPAQUE_INT
|
||||
}
|
||||
|
||||
private fun convertToDp(pixel: Int): Int {
|
||||
return dp(pixel.toFloat(), context)
|
||||
}
|
||||
|
||||
private fun dp(value: Float, context: Context): Int {
|
||||
if (density == DENSITY_DEFAULT) {
|
||||
checkDisplaySize(context)
|
||||
}
|
||||
return if (value == DENSITY_ZERO) {
|
||||
DENSITY_ZERO_INT
|
||||
} else {
|
||||
ceil((density * value).toDouble()).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("Detekt.TooGenericExceptionCaught")
|
||||
private fun checkDisplaySize(context: Context) {
|
||||
try {
|
||||
density = context.resources.displayMetrics.density
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Error calculating density", e)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "MessageSwipeCallback"
|
||||
const val NO_SWIPE_FLAG: Int = 0
|
||||
const val FULLY_OPAQUE: Float = 255f
|
||||
const val FULLY_OPAQUE_INT: Int = 255
|
||||
const val DENSITY_DEFAULT: Float = 1f
|
||||
const val DENSITY_ZERO: Float = 0f
|
||||
const val DENSITY_ZERO_INT: Int = 0
|
||||
const val REPLY_POINT: Int = 100
|
||||
const val SWIPE_LIMIT: Int = 130
|
||||
const val SHOW_REPLY_ICON_POINT: Int = 30
|
||||
const val MIN_ANIMATION_TIME_IN_MILLIS: Long = 17
|
||||
const val FULL_PROGRESS: Float = 1.0f
|
||||
const val NO_PROGRESS: Float = 0.0f
|
||||
const val PROGRESS_THRESHOLD: Float = 0.1f
|
||||
const val PROGRESS_CALCULATION_TIME_BASE: Float = 180.0f
|
||||
const val SCALE_PROGRESS_MULTIPLIER: Float = 1.2f
|
||||
const val SCALE_PROGRESS_TOP_THRESHOLD: Float = 0.8f
|
||||
const val SCALE_PROGRESS_BOTTOM_THRESHOLD: Float = 0.2f
|
||||
const val AXIS_BASE: Int = 2
|
||||
const val BACKGROUND_BOUNDS_PIXEL: Int = 18
|
||||
const val ICON_BOUNDS_PIXEL_LEFT: Int = 12
|
||||
const val ICON_BOUNDS_PIXEL_TOP: Int = 13
|
||||
const val ICON_BOUNDS_PIXEL_RIGHT: Int = 12
|
||||
const val ICON_BOUNDS_PIXEL_BOTTOM: Int = 11
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
build:
|
||||
maxIssues: 201
|
||||
maxIssues: 202
|
||||
weights:
|
||||
# complexity: 2
|
||||
# LongParameterList: 1
|
||||
|
|
Loading…
Reference in a new issue