|
@@ -60,11 +60,7 @@ import kotlin.math.min
|
|
|
class MessageSwipeCallback(private val context: Context, private val messageSwipeActions: MessageSwipeActions) :
|
|
|
ItemTouchHelper.Callback() {
|
|
|
|
|
|
- companion object {
|
|
|
- const val TAG = "MessageSwipeCallback"
|
|
|
- }
|
|
|
-
|
|
|
- private var density = 1f
|
|
|
+ private var density = DENSITY_DEFAULT
|
|
|
|
|
|
private lateinit var imageDrawable: Drawable
|
|
|
private lateinit var shareRound: Drawable
|
|
@@ -73,7 +69,7 @@ class MessageSwipeCallback(private val context: Context, private val messageSwip
|
|
|
private lateinit var view: View
|
|
|
private var dX = 0f
|
|
|
|
|
|
- private var replyButtonProgress: Float = 0.toFloat()
|
|
|
+ private var replyButtonProgress: Float = NO_PROGRESS
|
|
|
private var lastReplyButtonAnimationTime: Long = 0
|
|
|
private var swipeBack = false
|
|
|
private var isVibrate = false
|
|
@@ -91,7 +87,7 @@ class MessageSwipeCallback(private val context: Context, private val messageSwip
|
|
|
}
|
|
|
|
|
|
// disable swiping any other message type
|
|
|
- return 0
|
|
|
+ return NO_SWIPE_FLAG
|
|
|
}
|
|
|
|
|
|
override fun onMove(
|
|
@@ -126,7 +122,7 @@ class MessageSwipeCallback(private val context: Context, private val messageSwip
|
|
|
setTouchListener(recyclerView, viewHolder)
|
|
|
}
|
|
|
|
|
|
- if (view.translationX < convertToDp(130) || dX < this.dX) {
|
|
|
+ if (view.translationX < convertToDp(SWIPE_LIMIT) || dX < this.dX) {
|
|
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
|
|
this.dX = dX
|
|
|
startTracking = true
|
|
@@ -140,7 +136,7 @@ class MessageSwipeCallback(private val context: Context, private val messageSwip
|
|
|
recyclerView.setOnTouchListener { _, event ->
|
|
|
swipeBack = event.action == MotionEvent.ACTION_CANCEL || event.action == MotionEvent.ACTION_UP
|
|
|
if (swipeBack) {
|
|
|
- if (abs(view.translationX) >= this@MessageSwipeCallback.convertToDp(100)) {
|
|
|
+ if (abs(view.translationX) >= this@MessageSwipeCallback.convertToDp(REPLY_POINT)) {
|
|
|
messageSwipeActions.showReplyUI(viewHolder.adapterPosition)
|
|
|
}
|
|
|
}
|
|
@@ -154,27 +150,27 @@ class MessageSwipeCallback(private val context: Context, private val messageSwip
|
|
|
}
|
|
|
val translationX = view.translationX
|
|
|
val newTime = System.currentTimeMillis()
|
|
|
- val dt = min(17, newTime - lastReplyButtonAnimationTime)
|
|
|
+ val dt = min(MIN_ANIMATION_TIME_IN_MILLIS, newTime - lastReplyButtonAnimationTime)
|
|
|
lastReplyButtonAnimationTime = newTime
|
|
|
- val showing = translationX >= convertToDp(30)
|
|
|
+ val showing = translationX >= convertToDp(SHOW_REPLY_ICON_POINT)
|
|
|
if (showing) {
|
|
|
- if (replyButtonProgress < 1.0f) {
|
|
|
- replyButtonProgress += dt / 180.0f
|
|
|
- if (replyButtonProgress > 1.0f) {
|
|
|
- replyButtonProgress = 1.0f
|
|
|
+ if (replyButtonProgress < FULL_PROGRESS) {
|
|
|
+ replyButtonProgress += dt / PROGRESS_CALCULATION_TIME_BASE
|
|
|
+ if (replyButtonProgress > FULL_PROGRESS) {
|
|
|
+ replyButtonProgress = FULL_PROGRESS
|
|
|
} else {
|
|
|
view.invalidate()
|
|
|
}
|
|
|
}
|
|
|
- } else if (translationX <= 0.0f) {
|
|
|
- replyButtonProgress = 0f
|
|
|
+ } else if (translationX <= NO_PROGRESS) {
|
|
|
+ replyButtonProgress = NO_PROGRESS
|
|
|
startTracking = false
|
|
|
isVibrate = false
|
|
|
} else {
|
|
|
- if (replyButtonProgress > 0.0f) {
|
|
|
- replyButtonProgress -= dt / 180.0f
|
|
|
- if (replyButtonProgress < 0.1f) {
|
|
|
- replyButtonProgress = 0f
|
|
|
+ if (replyButtonProgress > NO_PROGRESS) {
|
|
|
+ replyButtonProgress -= dt / PROGRESS_CALCULATION_TIME_BASE
|
|
|
+ if (replyButtonProgress < PROGRESS_THRESHOLD) {
|
|
|
+ replyButtonProgress = NO_PROGRESS
|
|
|
} else {
|
|
|
view.invalidate()
|
|
|
}
|
|
@@ -184,21 +180,23 @@ class MessageSwipeCallback(private val context: Context, private val messageSwip
|
|
|
val alpha: Int
|
|
|
val scale: Float
|
|
|
if (showing) {
|
|
|
- scale = if (replyButtonProgress <= 0.8f) {
|
|
|
- 1.2f * (replyButtonProgress / 0.8f)
|
|
|
+ scale = if (replyButtonProgress <= SCALE_PROGRESS_TOP_THRESHOLD) {
|
|
|
+ SCALE_PROGRESS_MULTIPLIER * (replyButtonProgress / SCALE_PROGRESS_TOP_THRESHOLD)
|
|
|
} else {
|
|
|
- 1.2f - 0.2f * ((replyButtonProgress - 0.8f) / 0.2f)
|
|
|
+ SCALE_PROGRESS_MULTIPLIER -
|
|
|
+ SCALE_PROGRESS_BOTTOM_THRESHOLD *
|
|
|
+ ((replyButtonProgress - SCALE_PROGRESS_TOP_THRESHOLD) / SCALE_PROGRESS_BOTTOM_THRESHOLD)
|
|
|
}
|
|
|
- alpha = min(255f, 255 * (replyButtonProgress / 0.8f)).toInt()
|
|
|
+ alpha = min(FULLY_OPAQUE, FULLY_OPAQUE * (replyButtonProgress / SCALE_PROGRESS_TOP_THRESHOLD)).toInt()
|
|
|
} else {
|
|
|
scale = replyButtonProgress
|
|
|
- alpha = min(255f, 255 * replyButtonProgress).toInt()
|
|
|
+ alpha = min(FULLY_OPAQUE, FULLY_OPAQUE * replyButtonProgress).toInt()
|
|
|
}
|
|
|
shareRound.alpha = alpha
|
|
|
imageDrawable.alpha = alpha
|
|
|
|
|
|
if (startTracking) {
|
|
|
- if (!isVibrate && view.translationX >= convertToDp(100)) {
|
|
|
+ if (!isVibrate && view.translationX >= convertToDp(REPLY_POINT)) {
|
|
|
view.performHapticFeedback(
|
|
|
HapticFeedbackConstants.KEYBOARD_TAP,
|
|
|
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
|
|
@@ -207,13 +205,13 @@ class MessageSwipeCallback(private val context: Context, private val messageSwip
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- val x: Int = if (view.translationX > convertToDp(130)) {
|
|
|
- convertToDp(130) / 2
|
|
|
+ val x: Int = if (view.translationX > convertToDp(SWIPE_LIMIT)) {
|
|
|
+ convertToDp(SWIPE_LIMIT) / AXIS_BASE
|
|
|
} else {
|
|
|
- (view.translationX / 2).toInt()
|
|
|
+ (view.translationX / AXIS_BASE).toInt()
|
|
|
}
|
|
|
|
|
|
- val y = (view.top + view.measuredHeight / 2).toFloat()
|
|
|
+ val y = (view.top + view.measuredHeight / AXIS_BASE).toFloat()
|
|
|
shareRound.colorFilter = PorterDuffColorFilter(
|
|
|
ContextCompat.getColor(context, R.color.bg_message_list_incoming_bubble),
|
|
|
PorterDuff.Mode.SRC_IN
|
|
@@ -224,23 +222,23 @@ class MessageSwipeCallback(private val context: Context, private val messageSwip
|
|
|
)
|
|
|
|
|
|
shareRound.setBounds(
|
|
|
- (x - convertToDp(18) * scale).toInt(),
|
|
|
- (y - convertToDp(18) * scale).toInt(),
|
|
|
- (x + convertToDp(18) * scale).toInt(),
|
|
|
- (y + convertToDp(18) * scale).toInt()
|
|
|
+ (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(12) * scale).toInt(),
|
|
|
- (y - convertToDp(13) * scale).toInt(),
|
|
|
- (x + convertToDp(12) * scale).toInt(),
|
|
|
- (y + convertToDp(11) * scale).toInt()
|
|
|
+ (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 = 255
|
|
|
- imageDrawable.alpha = 255
|
|
|
+ shareRound.alpha = FULLY_OPAQUE_INT
|
|
|
+ imageDrawable.alpha = FULLY_OPAQUE_INT
|
|
|
}
|
|
|
|
|
|
private fun convertToDp(pixel: Int): Int {
|
|
@@ -248,11 +246,11 @@ class MessageSwipeCallback(private val context: Context, private val messageSwip
|
|
|
}
|
|
|
|
|
|
private fun dp(value: Float, context: Context): Int {
|
|
|
- if (density == 1f) {
|
|
|
+ if (density == DENSITY_DEFAULT) {
|
|
|
checkDisplaySize(context)
|
|
|
}
|
|
|
- return if (value == 0f) {
|
|
|
- 0
|
|
|
+ return if (value == DENSITY_ZERO) {
|
|
|
+ DENSITY_ZERO_INT
|
|
|
} else {
|
|
|
ceil((density * value).toDouble()).toInt()
|
|
|
}
|
|
@@ -265,4 +263,31 @@ class MessageSwipeCallback(private val context: Context, private val messageSwip
|
|
|
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
|
|
|
+ }
|
|
|
}
|