More animation

This commit is contained in:
Niels Andriesse 2021-06-17 10:53:56 +10:00
parent 4587f40128
commit 7cacee8499
5 changed files with 74 additions and 5 deletions

View File

@ -2,19 +2,23 @@ package org.thoughtcrime.securesms.conversation.v2
import android.animation.FloatEvaluator
import android.animation.ValueAnimator
import android.content.res.Resources
import android.database.Cursor
import android.os.Bundle
import android.util.Log
import android.view.ActionMode
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.widget.RelativeLayout
import androidx.core.view.isVisible
import androidx.loader.app.LoaderManager
import androidx.loader.content.Loader
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_conversation_v2.*
import kotlinx.android.synthetic.main.activity_conversation_v2.view.*
import kotlinx.android.synthetic.main.activity_conversation_v2_action_bar.*
import kotlinx.android.synthetic.main.view_input_bar.view.*
import kotlinx.android.synthetic.main.view_input_bar_recording.view.*
import network.loki.messenger.R
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarDelegate
@ -22,8 +26,9 @@ import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCa
import org.thoughtcrime.securesms.conversation.v2.menus.ConversationMenuHelper
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.loki.views.NewConversationButtonSetView
import org.thoughtcrime.securesms.mms.GlideApp
import kotlin.math.abs
import kotlin.math.sqrt
class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDelegate {
private var threadID: Long = -1
@ -57,6 +62,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
private val glide by lazy { GlideApp.with(this) }
private val screenWidth by lazy {
Resources.getSystem().displayMetrics.widthPixels
}
// region Settings
companion object {
const val THREAD_ID = "thread_id"
@ -167,5 +176,45 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
}
}
}
override fun onMicrophoneButtonMove(event: MotionEvent) {
val rawX = event.rawX
val chevronImageView = inputBarRecordingView.inputBarChevronImageView
val slideToCancelTextView = inputBarRecordingView.inputBarSlideToCancelTextView
if (rawX < screenWidth / 2) {
val translationX = rawX - screenWidth / 2
val sign = -1.0f
val chevronDamping = 4.0f
val labelDamping = 3.0f
val chevronX = (chevronDamping * (sqrt(abs(translationX)) / sqrt(chevronDamping))) * sign
val labelX = (labelDamping * (sqrt(abs(translationX)) / sqrt(labelDamping))) * sign
chevronImageView.translationX = chevronX
slideToCancelTextView.translationX = labelX
} else {
chevronImageView.translationX = 0.0f
slideToCancelTextView.translationX = 0.0f
}
}
override fun onMicrophoneButtonCancel(event: MotionEvent) {
resetVoiceMessageUI()
}
override fun onMicrophoneButtonUp(event: MotionEvent) {
resetVoiceMessageUI()
}
private fun resetVoiceMessageUI() {
val chevronImageView = inputBarRecordingView.inputBarChevronImageView
val slideToCancelTextView = inputBarRecordingView.inputBarSlideToCancelTextView
listOf( chevronImageView, slideToCancelTextView ).forEach { view ->
val animation = ValueAnimator.ofObject(FloatEvaluator(), view.translationX, 0.0f)
animation.duration = 250L
animation.addUpdateListener { animator ->
view.translationX = animator.animatedValue as Float
}
animation.start()
}
}
// endregion
}

View File

@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.conversation.v2.input_bar
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.MotionEvent
import android.widget.RelativeLayout
import androidx.core.view.isVisible
import kotlinx.android.synthetic.main.view_input_bar.view.*
@ -34,6 +35,9 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate {
microphoneButton.onLongPress = {
showVoiceMessageUI()
}
microphoneButton.onMove = { delegate?.onMicrophoneButtonMove(it) }
microphoneButton.onCancel = { delegate?.onMicrophoneButtonCancel(it) }
microphoneButton.onUp = { delegate?.onMicrophoneButtonUp(it) }
// Send button
microphoneOrSendButtonContainer.addView(sendButton)
sendButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
@ -69,4 +73,7 @@ interface InputBarDelegate {
fun inputBarHeightChanged(newValue: Int)
fun showVoiceMessageUI()
fun onMicrophoneButtonMove(event: MotionEvent)
fun onMicrophoneButtonCancel(event: MotionEvent)
fun onMicrophoneButtonUp(event: MotionEvent)
}

View File

@ -32,6 +32,9 @@ class InputBarButton : RelativeLayout {
private var onDownTimestamp = 0L
var onPress: (() -> Unit)? = null
var onMove: ((MotionEvent) -> Unit)? = null
var onCancel: ((MotionEvent) -> Unit)? = null
var onUp: ((MotionEvent) -> Unit)? = null
var onLongPress: (() -> Unit)? = null
companion object {
@ -112,6 +115,7 @@ class InputBarButton : RelativeLayout {
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> onDown(event)
MotionEvent.ACTION_MOVE -> onMove(event)
MotionEvent.ACTION_UP -> onUp(event)
MotionEvent.ACTION_CANCEL -> onCancel(event)
}
@ -132,12 +136,18 @@ class InputBarButton : RelativeLayout {
onDownTimestamp = Date().time
}
private fun onMove(event: MotionEvent) {
onMove?.invoke(event)
}
private fun onCancel(event: MotionEvent) {
onCancel?.invoke(event)
collapse()
longPressCallback?.let { gestureHandler.removeCallbacks(it) }
}
private fun onUp(event: MotionEvent) {
onUp?.invoke(event)
collapse()
if ((Date().time - onDownTimestamp) < VisibleMessageView.longPressDurationThreshold) {
longPressCallback?.let { gestureHandler.removeCallbacks(it) }

View File

@ -1,19 +1,17 @@
package org.thoughtcrime.securesms.conversation.v2.input_bar
import android.animation.Animator
import android.animation.FloatEvaluator
import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.widget.RelativeLayout
import androidx.core.view.isVisible
import kotlinx.android.synthetic.main.view_input_bar_recording.view.*
import network.loki.messenger.R
import org.thoughtcrime.securesms.loki.utilities.animateSizeChange
import org.thoughtcrime.securesms.loki.utilities.disableClipping
import org.thoughtcrime.securesms.loki.utilities.toPx
import kotlin.math.roundToInt
class InputBarRecordingView : RelativeLayout {
@ -23,6 +21,7 @@ class InputBarRecordingView : RelativeLayout {
private fun initialize() {
LayoutInflater.from(context).inflate(R.layout.view_input_bar_recording, this)
inputBarMiddleContentContainer.disableClipping()
}
fun show() {

View File

@ -50,13 +50,16 @@
<!-- The middle content (left arrow + slide to cancel) -->
<LinearLayout
android:id="@+id/inputBarMiddleContentContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:paddingHorizontal="40dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<ImageView
android:id="@+id/inputBarChevronImageView"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/ic_keyboard_arrow_left_grey600_24dp"
@ -65,6 +68,7 @@
android:alpha="0.6" />
<TextView
android:id="@+id/inputBarSlideToCancelTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"