diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
index 76b513509a..13cad79ae6 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
@@ -6,6 +6,7 @@ import android.view.ActionMode
import android.view.Menu
import android.view.MenuItem
import android.widget.RelativeLayout
+import androidx.core.view.isVisible
import androidx.loader.app.LoaderManager
import androidx.loader.content.Loader
import androidx.recyclerview.widget.LinearLayoutManager
@@ -112,6 +113,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
recyclerViewLayoutParams.bottomMargin = newValue
conversationRecyclerView.layoutParams = recyclerViewLayoutParams
}
+
+ override fun showVoiceMessageUI() {
+ inputBarRecordingView.isVisible = true
+ }
// endregion
// region Interaction
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt
index 9593bd888b..00af1e6198 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt
@@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.conversation.v2.input_bar
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
-import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.core.view.isVisible
import kotlinx.android.synthetic.main.view_input_bar.view.*
@@ -12,7 +11,7 @@ import org.thoughtcrime.securesms.loki.utilities.toDp
import org.thoughtcrime.securesms.loki.utilities.toPx
import kotlin.math.max
-class InputBar : LinearLayout, InputBarEditTextDelegate {
+class InputBar : RelativeLayout, InputBarEditTextDelegate {
var delegate: InputBarDelegate? = null
private val attachmentsButton by lazy { InputBarButton(context, R.drawable.ic_plus_24) }
@@ -20,30 +19,26 @@ class InputBar : LinearLayout, InputBarEditTextDelegate {
private val sendButton by lazy { InputBarButton(context, R.drawable.ic_arrow_up, true) }
// region Lifecycle
- constructor(context: Context) : super(context) {
- setUpViewHierarchy()
- }
+ constructor(context: Context) : super(context) { initialize() }
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() }
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() }
- constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- setUpViewHierarchy()
- }
-
- constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
- setUpViewHierarchy()
- }
-
- private fun setUpViewHierarchy() {
+ private fun initialize() {
LayoutInflater.from(context).inflate(R.layout.view_input_bar, this)
+ // Attachments button
attachmentsButtonContainer.addView(attachmentsButton)
attachmentsButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
- attachmentsButton.setOnClickListener { }
+ // Microphone button
microphoneOrSendButtonContainer.addView(microphoneButton)
microphoneButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
- microphoneButton.setOnClickListener { }
+ microphoneButton.onLongPress = {
+ showVoiceMessageUI()
+ }
+ // Send button
microphoneOrSendButtonContainer.addView(sendButton)
sendButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
- sendButton.setOnClickListener { }
sendButton.isVisible = false
+ // Edit text
inputBarEditText.imeOptions = inputBarEditText.imeOptions or 16777216 // Always use incognito keyboard
inputBarEditText.delegate = this
}
@@ -63,10 +58,15 @@ class InputBar : LinearLayout, InputBarEditTextDelegate {
inputBarLinearLayout.layoutParams = layoutParams
delegate?.inputBarHeightChanged(newHeight)
}
+
+ private fun showVoiceMessageUI() {
+ delegate?.showVoiceMessageUI()
+ }
// endregion
}
interface InputBarDelegate {
fun inputBarHeightChanged(newValue: Int)
+ fun showVoiceMessageUI()
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarButton.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarButton.kt
index a9f4732543..f42273b482 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarButton.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarButton.kt
@@ -6,7 +6,10 @@ import android.content.Context
import android.content.res.ColorStateList
import android.graphics.PointF
import android.os.Build
+import android.os.Handler
+import android.os.Looper
import android.util.AttributeSet
+import android.util.Log
import android.view.Gravity
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
@@ -14,13 +17,22 @@ import android.widget.ImageView
import android.widget.RelativeLayout
import androidx.annotation.DrawableRes
import network.loki.messenger.R
+import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView
import org.thoughtcrime.securesms.loki.utilities.*
import org.thoughtcrime.securesms.loki.views.GlowViewUtilities
import org.thoughtcrime.securesms.loki.views.InputBarButtonImageViewContainer
+import java.util.*
+import kotlin.math.abs
class InputBarButton : RelativeLayout {
+ private val gestureHandler = Handler(Looper.getMainLooper())
private var isSendButton = false
@DrawableRes private var iconID = 0
+ private var longPressCallback: Runnable? = null
+ private var onDownTimestamp = 0L
+
+ var onPress: (() -> Unit)? = null
+ var onLongPress: (() -> Unit)? = null
companion object {
val animationDuration = 250.toLong()
@@ -99,16 +111,37 @@ class InputBarButton : RelativeLayout {
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
- MotionEvent.ACTION_DOWN -> {
- expand()
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
- } else {
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
- }
- }
- MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { collapse() }
+ MotionEvent.ACTION_DOWN -> onDown(event)
+ MotionEvent.ACTION_UP -> onUp(event)
+ MotionEvent.ACTION_CANCEL -> onCancel(event)
}
return true
}
+
+ private fun onDown(event: MotionEvent) {
+ expand()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
+ } else {
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
+ }
+ longPressCallback?.let { gestureHandler.removeCallbacks(it) }
+ val newLongPressCallback = Runnable { onLongPress?.invoke() }
+ this.longPressCallback = newLongPressCallback
+ gestureHandler.postDelayed(newLongPressCallback, VisibleMessageView.longPressDurationThreshold)
+ onDownTimestamp = Date().time
+ }
+
+ private fun onCancel(event: MotionEvent) {
+ collapse()
+ longPressCallback?.let { gestureHandler.removeCallbacks(it) }
+ }
+
+ private fun onUp(event: MotionEvent) {
+ collapse()
+ if ((Date().time - onDownTimestamp) < VisibleMessageView.longPressDurationThreshold) {
+ longPressCallback?.let { gestureHandler.removeCallbacks(it) }
+ onPress?.invoke()
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarRecordingView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarRecordingView.kt
new file mode 100644
index 0000000000..ffcb403ab7
--- /dev/null
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBarRecordingView.kt
@@ -0,0 +1,18 @@
+package org.thoughtcrime.securesms.conversation.v2.input_bar
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.RelativeLayout
+import network.loki.messenger.R
+
+class InputBarRecordingView : RelativeLayout {
+
+ constructor(context: Context) : super(context) { initialize() }
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() }
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() }
+
+ private fun initialize() {
+ LayoutInflater.from(context).inflate(R.layout.view_input_bar_recording, this)
+ }
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt
index 5d8ef91856..1b26830350 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt
@@ -230,18 +230,7 @@ class VisibleMessageView : LinearLayout {
private fun onCancel(event: MotionEvent) {
longPressCallback?.let { gestureHandler.removeCallbacks(it) }
- animate()
- .translationX(0.0f)
- .setDuration(150)
- .setUpdateListener {
- postInvalidate() // Ensure onDraw(canvas:) is called
- }
- .start()
- // Bit of a hack to keep the date break text view from moving
- dateBreakTextView.animate()
- .translationX(0.0f)
- .setDuration(150)
- .start()
+ resetPosition()
}
private fun onUp(event: MotionEvent) {
@@ -251,6 +240,10 @@ class VisibleMessageView : LinearLayout {
longPressCallback?.let { gestureHandler.removeCallbacks(it) }
onPress?.invoke()
}
+ resetPosition()
+ }
+
+ private fun resetPosition() {
animate()
.translationX(0.0f)
.setDuration(150)
@@ -260,9 +253,9 @@ class VisibleMessageView : LinearLayout {
.start()
// Bit of a hack to keep the date break text view from moving
dateBreakTextView.animate()
- .translationX(0.0f)
- .setDuration(150)
- .start()
+ .translationX(0.0f)
+ .setDuration(150)
+ .start()
}
private fun onLongPress() {
diff --git a/app/src/main/res/layout/activity_conversation_v2.xml b/app/src/main/res/layout/activity_conversation_v2.xml
index bc483643b8..d50a07e101 100644
--- a/app/src/main/res/layout/activity_conversation_v2.xml
+++ b/app/src/main/res/layout/activity_conversation_v2.xml
@@ -18,4 +18,12 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_input_bar_recording.xml b/app/src/main/res/layout/view_input_bar_recording.xml
new file mode 100644
index 0000000000..f0e10cf7c2
--- /dev/null
+++ b/app/src/main/res/layout/view_input_bar_recording.xml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file