mirror of
https://github.com/oxen-io/session-android.git
synced 2025-01-12 12:43:39 +00:00
More animation
This commit is contained in:
parent
4587f40128
commit
7cacee8499
@ -2,19 +2,23 @@ package org.thoughtcrime.securesms.conversation.v2
|
|||||||
|
|
||||||
import android.animation.FloatEvaluator
|
import android.animation.FloatEvaluator
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
|
import android.content.res.Resources
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.ActionMode
|
import android.view.ActionMode
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.loader.app.LoaderManager
|
import androidx.loader.app.LoaderManager
|
||||||
import androidx.loader.content.Loader
|
import androidx.loader.content.Loader
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import kotlinx.android.synthetic.main.activity_conversation_v2.*
|
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.activity_conversation_v2_action_bar.*
|
||||||
import kotlinx.android.synthetic.main.view_input_bar.view.*
|
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 network.loki.messenger.R
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||||
import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarDelegate
|
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.conversation.v2.menus.ConversationMenuHelper
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||||
import org.thoughtcrime.securesms.loki.views.NewConversationButtonSetView
|
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp
|
import org.thoughtcrime.securesms.mms.GlideApp
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDelegate {
|
class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDelegate {
|
||||||
private var threadID: Long = -1
|
private var threadID: Long = -1
|
||||||
@ -57,6 +62,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
|
|
||||||
private val glide by lazy { GlideApp.with(this) }
|
private val glide by lazy { GlideApp.with(this) }
|
||||||
|
|
||||||
|
private val screenWidth by lazy {
|
||||||
|
Resources.getSystem().displayMetrics.widthPixels
|
||||||
|
}
|
||||||
|
|
||||||
// region Settings
|
// region Settings
|
||||||
companion object {
|
companion object {
|
||||||
const val THREAD_ID = "thread_id"
|
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
|
// endregion
|
||||||
}
|
}
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.conversation.v2.input_bar
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import kotlinx.android.synthetic.main.view_input_bar.view.*
|
import kotlinx.android.synthetic.main.view_input_bar.view.*
|
||||||
@ -34,6 +35,9 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate {
|
|||||||
microphoneButton.onLongPress = {
|
microphoneButton.onLongPress = {
|
||||||
showVoiceMessageUI()
|
showVoiceMessageUI()
|
||||||
}
|
}
|
||||||
|
microphoneButton.onMove = { delegate?.onMicrophoneButtonMove(it) }
|
||||||
|
microphoneButton.onCancel = { delegate?.onMicrophoneButtonCancel(it) }
|
||||||
|
microphoneButton.onUp = { delegate?.onMicrophoneButtonUp(it) }
|
||||||
// Send button
|
// Send button
|
||||||
microphoneOrSendButtonContainer.addView(sendButton)
|
microphoneOrSendButtonContainer.addView(sendButton)
|
||||||
sendButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
|
sendButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
|
||||||
@ -69,4 +73,7 @@ interface InputBarDelegate {
|
|||||||
|
|
||||||
fun inputBarHeightChanged(newValue: Int)
|
fun inputBarHeightChanged(newValue: Int)
|
||||||
fun showVoiceMessageUI()
|
fun showVoiceMessageUI()
|
||||||
|
fun onMicrophoneButtonMove(event: MotionEvent)
|
||||||
|
fun onMicrophoneButtonCancel(event: MotionEvent)
|
||||||
|
fun onMicrophoneButtonUp(event: MotionEvent)
|
||||||
}
|
}
|
@ -32,6 +32,9 @@ class InputBarButton : RelativeLayout {
|
|||||||
private var onDownTimestamp = 0L
|
private var onDownTimestamp = 0L
|
||||||
|
|
||||||
var onPress: (() -> Unit)? = null
|
var onPress: (() -> Unit)? = null
|
||||||
|
var onMove: ((MotionEvent) -> Unit)? = null
|
||||||
|
var onCancel: ((MotionEvent) -> Unit)? = null
|
||||||
|
var onUp: ((MotionEvent) -> Unit)? = null
|
||||||
var onLongPress: (() -> Unit)? = null
|
var onLongPress: (() -> Unit)? = null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -112,6 +115,7 @@ class InputBarButton : RelativeLayout {
|
|||||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||||
when (event.action) {
|
when (event.action) {
|
||||||
MotionEvent.ACTION_DOWN -> onDown(event)
|
MotionEvent.ACTION_DOWN -> onDown(event)
|
||||||
|
MotionEvent.ACTION_MOVE -> onMove(event)
|
||||||
MotionEvent.ACTION_UP -> onUp(event)
|
MotionEvent.ACTION_UP -> onUp(event)
|
||||||
MotionEvent.ACTION_CANCEL -> onCancel(event)
|
MotionEvent.ACTION_CANCEL -> onCancel(event)
|
||||||
}
|
}
|
||||||
@ -132,12 +136,18 @@ class InputBarButton : RelativeLayout {
|
|||||||
onDownTimestamp = Date().time
|
onDownTimestamp = Date().time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onMove(event: MotionEvent) {
|
||||||
|
onMove?.invoke(event)
|
||||||
|
}
|
||||||
|
|
||||||
private fun onCancel(event: MotionEvent) {
|
private fun onCancel(event: MotionEvent) {
|
||||||
|
onCancel?.invoke(event)
|
||||||
collapse()
|
collapse()
|
||||||
longPressCallback?.let { gestureHandler.removeCallbacks(it) }
|
longPressCallback?.let { gestureHandler.removeCallbacks(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onUp(event: MotionEvent) {
|
private fun onUp(event: MotionEvent) {
|
||||||
|
onUp?.invoke(event)
|
||||||
collapse()
|
collapse()
|
||||||
if ((Date().time - onDownTimestamp) < VisibleMessageView.longPressDurationThreshold) {
|
if ((Date().time - onDownTimestamp) < VisibleMessageView.longPressDurationThreshold) {
|
||||||
longPressCallback?.let { gestureHandler.removeCallbacks(it) }
|
longPressCallback?.let { gestureHandler.removeCallbacks(it) }
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
package org.thoughtcrime.securesms.conversation.v2.input_bar
|
package org.thoughtcrime.securesms.conversation.v2.input_bar
|
||||||
|
|
||||||
import android.animation.Animator
|
|
||||||
import android.animation.FloatEvaluator
|
import android.animation.FloatEvaluator
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import kotlinx.android.synthetic.main.view_input_bar_recording.view.*
|
import kotlinx.android.synthetic.main.view_input_bar_recording.view.*
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import org.thoughtcrime.securesms.loki.utilities.animateSizeChange
|
import org.thoughtcrime.securesms.loki.utilities.animateSizeChange
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.disableClipping
|
||||||
import org.thoughtcrime.securesms.loki.utilities.toPx
|
import org.thoughtcrime.securesms.loki.utilities.toPx
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
class InputBarRecordingView : RelativeLayout {
|
class InputBarRecordingView : RelativeLayout {
|
||||||
|
|
||||||
@ -23,6 +21,7 @@ class InputBarRecordingView : RelativeLayout {
|
|||||||
|
|
||||||
private fun initialize() {
|
private fun initialize() {
|
||||||
LayoutInflater.from(context).inflate(R.layout.view_input_bar_recording, this)
|
LayoutInflater.from(context).inflate(R.layout.view_input_bar_recording, this)
|
||||||
|
inputBarMiddleContentContainer.disableClipping()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun show() {
|
fun show() {
|
||||||
|
@ -50,13 +50,16 @@
|
|||||||
<!-- The middle content (left arrow + slide to cancel) -->
|
<!-- The middle content (left arrow + slide to cancel) -->
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/inputBarMiddleContentContainer"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
|
android:paddingHorizontal="40dp"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
android:id="@+id/inputBarChevronImageView"
|
||||||
android:layout_width="16dp"
|
android:layout_width="16dp"
|
||||||
android:layout_height="16dp"
|
android:layout_height="16dp"
|
||||||
android:src="@drawable/ic_keyboard_arrow_left_grey600_24dp"
|
android:src="@drawable/ic_keyboard_arrow_left_grey600_24dp"
|
||||||
@ -65,6 +68,7 @@
|
|||||||
android:alpha="0.6" />
|
android:alpha="0.6" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/inputBarSlideToCancelTextView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="4dp"
|
android:layout_marginLeft="4dp"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user