mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 13:38:49 +03:00
allows locking and cancelling to occur after choosing either option
- fixes other quirks caused by porting to the inverted display logic
This commit is contained in:
parent
e895dbd923
commit
9ae03b76cd
6 changed files with 69 additions and 67 deletions
|
@ -712,9 +712,10 @@ class RoomDetailFragment @Inject constructor(
|
||||||
roomDetailViewModel.handle(RoomDetailAction.PlayOrPauseRecordingPlayback)
|
roomDetailViewModel.handle(RoomDetailAction.PlayOrPauseRecordingPlayback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRecordingStopped() {
|
override fun onVoiceRecordingEnded(lastKnownState: RecordingUiState?) {
|
||||||
roomDetailViewModel.handle(RoomDetailAction.EndRecordingVoiceMessage(isCancelled = true))
|
if (lastKnownState != RecordingUiState.Locked) {
|
||||||
if (currentState() != RecordingUiState.Locked) {
|
val isCancelled = lastKnownState == RecordingUiState.Cancelled
|
||||||
|
roomDetailViewModel.handle(RoomDetailAction.EndRecordingVoiceMessage(isCancelled = isCancelled))
|
||||||
display(RecordingUiState.None)
|
display(RecordingUiState.None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -729,7 +730,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
|
|
||||||
override fun deleteVoiceMessage() {
|
override fun deleteVoiceMessage() {
|
||||||
roomDetailViewModel.handle(RoomDetailAction.EndRecordingVoiceMessage(isCancelled = true))
|
roomDetailViewModel.handle(RoomDetailAction.EndRecordingVoiceMessage(isCancelled = true))
|
||||||
display(RecordingUiState.Cancelled)
|
display(RecordingUiState.None)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRecordingLimitReached() {
|
override fun onRecordingLimitReached() {
|
||||||
|
@ -743,8 +744,6 @@ class RoomDetailFragment @Inject constructor(
|
||||||
private fun display(state: RecordingUiState) {
|
private fun display(state: RecordingUiState) {
|
||||||
textComposerViewModel.handle(TextComposerAction.OnVoiceRecordingUiStateChanged(state))
|
textComposerViewModel.handle(TextComposerAction.OnVoiceRecordingUiStateChanged(state))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun currentState() = withState(textComposerViewModel) { it.voiceRecordingUiState }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1986,7 +1985,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
roomDetailViewModel.handle(RoomDetailAction.UpdateQuickReactAction(action.eventId, action.clickedOn, action.add))
|
roomDetailViewModel.handle(RoomDetailAction.UpdateQuickReactAction(action.eventId, action.clickedOn, action.add))
|
||||||
}
|
}
|
||||||
is EventSharedAction.Edit -> {
|
is EventSharedAction.Edit -> {
|
||||||
if (!views.voiceMessageRecorderView.isActive()) {
|
if (withState(textComposerViewModel) { it.isVoiceMessageIdle }) {
|
||||||
textComposerViewModel.handle(TextComposerAction.EnterEditMode(action.eventId, views.composerLayout.text.toString()))
|
textComposerViewModel.handle(TextComposerAction.EnterEditMode(action.eventId, views.composerLayout.text.toString()))
|
||||||
} else {
|
} else {
|
||||||
requireActivity().toast(R.string.error_voice_message_cannot_reply_or_edit)
|
requireActivity().toast(R.string.error_voice_message_cannot_reply_or_edit)
|
||||||
|
@ -1996,7 +1995,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
textComposerViewModel.handle(TextComposerAction.EnterQuoteMode(action.eventId, views.composerLayout.text.toString()))
|
textComposerViewModel.handle(TextComposerAction.EnterQuoteMode(action.eventId, views.composerLayout.text.toString()))
|
||||||
}
|
}
|
||||||
is EventSharedAction.Reply -> {
|
is EventSharedAction.Reply -> {
|
||||||
if (!views.voiceMessageRecorderView.isActive()) {
|
if (withState(textComposerViewModel) { it.isVoiceMessageIdle }) {
|
||||||
textComposerViewModel.handle(TextComposerAction.EnterReplyMode(action.eventId, views.composerLayout.text.toString()))
|
textComposerViewModel.handle(TextComposerAction.EnterReplyMode(action.eventId, views.composerLayout.text.toString()))
|
||||||
} else {
|
} else {
|
||||||
requireActivity().toast(R.string.error_voice_message_cannot_reply_or_edit)
|
requireActivity().toast(R.string.error_voice_message_cannot_reply_or_edit)
|
||||||
|
|
|
@ -60,8 +60,14 @@ data class TextComposerViewState(
|
||||||
VoiceMessageRecorderView.RecordingUiState.Started -> true
|
VoiceMessageRecorderView.RecordingUiState.Started -> true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val isVoiceMessageIdle = when (voiceRecordingUiState) {
|
||||||
|
VoiceMessageRecorderView.RecordingUiState.None, VoiceMessageRecorderView.RecordingUiState.Cancelled -> false
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
|
||||||
val isComposerVisible = canSendMessage && !isVoiceRecording
|
val isComposerVisible = canSendMessage && !isVoiceRecording
|
||||||
val isVoiceMessageRecorderVisible = canSendMessage && !isSendButtonVisible
|
val isVoiceMessageRecorderVisible = canSendMessage && !isSendButtonVisible
|
||||||
|
|
||||||
|
@Suppress("UNUSED") // needed by mavericks
|
||||||
constructor(args: RoomDetailArgs) : this(roomId = args.roomId)
|
constructor(args: RoomDetailArgs) : this(roomId = args.roomId)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,23 +28,18 @@ class DraggableStateProcessor(
|
||||||
dimensionConverter: DimensionConverter,
|
dimensionConverter: DimensionConverter,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val minimumMove = dimensionConverter.dpToPx(16)
|
|
||||||
private val distanceToLock = dimensionConverter.dpToPx(48).toFloat()
|
private val distanceToLock = dimensionConverter.dpToPx(48).toFloat()
|
||||||
private val distanceToCancel = dimensionConverter.dpToPx(120).toFloat()
|
private val distanceToCancel = dimensionConverter.dpToPx(120).toFloat()
|
||||||
private val rtlXMultiplier = resources.getInteger(R.integer.rtl_x_multiplier)
|
private val rtlXMultiplier = resources.getInteger(R.integer.rtl_x_multiplier)
|
||||||
|
|
||||||
private var firstX: Float = 0f
|
private var firstX: Float = 0f
|
||||||
private var firstY: Float = 0f
|
private var firstY: Float = 0f
|
||||||
private var lastX: Float = 0f
|
|
||||||
private var lastY: Float = 0f
|
|
||||||
private var lastDistanceX: Float = 0f
|
private var lastDistanceX: Float = 0f
|
||||||
private var lastDistanceY: Float = 0f
|
private var lastDistanceY: Float = 0f
|
||||||
|
|
||||||
fun reset(event: MotionEvent) {
|
fun initialize(event: MotionEvent) {
|
||||||
firstX = event.rawX
|
firstX = event.rawX
|
||||||
firstY = event.rawY
|
firstY = event.rawY
|
||||||
lastX = firstX
|
|
||||||
lastY = firstY
|
|
||||||
lastDistanceX = 0F
|
lastDistanceX = 0F
|
||||||
lastDistanceY = 0F
|
lastDistanceY = 0F
|
||||||
}
|
}
|
||||||
|
@ -54,49 +49,48 @@ class DraggableStateProcessor(
|
||||||
val currentY = event.rawY
|
val currentY = event.rawY
|
||||||
val distanceX = firstX - currentX
|
val distanceX = firstX - currentX
|
||||||
val distanceY = firstY - currentY
|
val distanceY = firstY - currentY
|
||||||
return nextRecordingState(recordingState, currentX, currentY, distanceX, distanceY).also {
|
return recordingState.nextRecordingState(currentX, currentY, distanceX, distanceY).also {
|
||||||
lastX = currentX
|
|
||||||
lastY = currentY
|
|
||||||
lastDistanceX = distanceX
|
lastDistanceX = distanceX
|
||||||
lastDistanceY = distanceY
|
lastDistanceY = distanceY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nextRecordingState(recordingState: RecordingUiState, currentX: Float, currentY: Float, distanceX: Float, distanceY: Float): RecordingUiState {
|
private fun RecordingUiState.nextRecordingState(currentX: Float, currentY: Float, distanceX: Float, distanceY: Float): RecordingUiState {
|
||||||
return when (recordingState) {
|
return when (this) {
|
||||||
RecordingUiState.Started -> {
|
RecordingUiState.Started -> {
|
||||||
// Determine if cancelling or locking for the first move action.
|
|
||||||
when {
|
when {
|
||||||
(isSlidingToCancel(currentX)) && distanceX > distanceY && distanceX > lastDistanceX -> DraggingState.Cancelling(distanceX)
|
isDraggingToCancel(currentX, distanceX, distanceY) -> DraggingState.Cancelling(distanceX)
|
||||||
isSlidingToLock(currentY) && distanceY > distanceX && distanceY > lastDistanceY -> DraggingState.Locking(distanceY)
|
isDraggingToLock(currentY, distanceX, distanceY) -> DraggingState.Locking(distanceY)
|
||||||
else -> recordingState
|
else -> this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is DraggingState.Cancelling -> {
|
is DraggingState.Cancelling -> {
|
||||||
// Check if cancelling conditions met, also check if it should be initial state
|
|
||||||
when {
|
when {
|
||||||
distanceX < minimumMove && distanceX < lastDistanceX -> RecordingUiState.Started
|
isDraggingToLock(currentY, distanceX, distanceY) -> DraggingState.Locking(distanceY)
|
||||||
shouldCancelRecording(distanceX) -> RecordingUiState.Cancelled
|
shouldCancelRecording(distanceX) -> RecordingUiState.Cancelled
|
||||||
else -> DraggingState.Cancelling(distanceX)
|
else -> DraggingState.Cancelling(distanceX)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is DraggingState.Locking -> {
|
is DraggingState.Locking -> {
|
||||||
// Check if locking conditions met, also check if it should be initial state
|
|
||||||
when {
|
when {
|
||||||
distanceY < minimumMove && distanceY < lastDistanceY -> RecordingUiState.Started
|
isDraggingToCancel(currentX, distanceX, distanceY) -> DraggingState.Cancelling(distanceX)
|
||||||
shouldLockRecording(distanceY) -> RecordingUiState.Locked
|
shouldLockRecording(distanceY) -> RecordingUiState.Locked
|
||||||
else -> DraggingState.Locking(distanceY)
|
else -> DraggingState.Locking(distanceY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
recordingState
|
this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isSlidingToLock(currentY: Float) = currentY < firstY
|
private fun isDraggingToLock(currentY: Float, distanceX: Float, distanceY: Float) = (currentY < firstY) &&
|
||||||
|
distanceY > distanceX && distanceY > lastDistanceY
|
||||||
|
|
||||||
private fun isSlidingToCancel(currentX: Float) = (currentX < firstX && rtlXMultiplier == 1) || (currentX > firstX && rtlXMultiplier == -1)
|
private fun isDraggingToCancel(currentX: Float, distanceX: Float, distanceY: Float) = isDraggingHorizontal(currentX) &&
|
||||||
|
distanceX > distanceY && distanceX > lastDistanceX
|
||||||
|
|
||||||
|
private fun isDraggingHorizontal(currentX: Float) = (currentX < firstX && rtlXMultiplier == 1) || (currentX > firstX && rtlXMultiplier == -1)
|
||||||
|
|
||||||
private fun shouldCancelRecording(distanceX: Float): Boolean {
|
private fun shouldCancelRecording(distanceX: Float): Boolean {
|
||||||
return distanceX >= distanceToCancel
|
return distanceX >= distanceToCancel
|
||||||
|
@ -106,4 +100,3 @@ class DraggableStateProcessor(
|
||||||
return distanceY >= distanceToLock
|
return distanceY >= distanceToLock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,13 +43,12 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
fun onVoiceRecordingStarted()
|
fun onVoiceRecordingStarted()
|
||||||
fun onVoiceRecordingPlaybackModeOn()
|
fun onVoiceRecordingPlaybackModeOn()
|
||||||
fun onVoicePlaybackButtonClicked()
|
fun onVoicePlaybackButtonClicked()
|
||||||
fun onRecordingStopped()
|
|
||||||
fun onUiStateChanged(state: RecordingUiState)
|
fun onUiStateChanged(state: RecordingUiState)
|
||||||
fun sendVoiceMessage()
|
fun sendVoiceMessage()
|
||||||
fun deleteVoiceMessage()
|
fun deleteVoiceMessage()
|
||||||
fun onRecordingLimitReached()
|
fun onRecordingLimitReached()
|
||||||
fun recordingWaveformClicked()
|
fun recordingWaveformClicked()
|
||||||
fun currentState(): RecordingUiState
|
fun onVoiceRecordingEnded(lastKnownState: RecordingUiState?)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to define views as lateinit var to be able to check if initialized for the bug fix on api 21 and 22.
|
// We need to define views as lateinit var to be able to check if initialized for the bug fix on api 21 and 22.
|
||||||
|
@ -85,17 +84,23 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
callback.onVoiceRecordingStarted()
|
callback.onVoiceRecordingStarted()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRecordingStopped() {
|
override fun onMicButtonReleased() {
|
||||||
callback.onRecordingStopped()
|
callback.onVoiceRecordingEnded(lastKnownState)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isActive() = callback.currentState() != RecordingUiState.Cancelled
|
|
||||||
|
|
||||||
override fun updateState(updater: (RecordingUiState) -> RecordingUiState) {
|
override fun updateState(updater: (RecordingUiState) -> RecordingUiState) {
|
||||||
updater(lastKnownState ?: RecordingUiState.None).also { newState ->
|
when (val currentState = lastKnownState) {
|
||||||
when (newState) {
|
null, RecordingUiState.None -> {
|
||||||
is DraggingState -> display(newState)
|
// ignore drag events when the view is idle
|
||||||
else -> callback.onUiStateChanged(newState)
|
}
|
||||||
|
else -> {
|
||||||
|
updater(currentState).also { newState ->
|
||||||
|
when (newState) {
|
||||||
|
// display drag events directly without leaving the view for faster UI feedback
|
||||||
|
is DraggingState -> display(newState)
|
||||||
|
else -> callback.onUiStateChanged(newState)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,6 +125,7 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
|
|
||||||
fun display(recordingState: RecordingUiState) {
|
fun display(recordingState: RecordingUiState) {
|
||||||
if (lastKnownState == recordingState) return
|
if (lastKnownState == recordingState) return
|
||||||
|
val previousState = lastKnownState
|
||||||
lastKnownState = recordingState
|
lastKnownState = recordingState
|
||||||
when (recordingState) {
|
when (recordingState) {
|
||||||
RecordingUiState.None -> {
|
RecordingUiState.None -> {
|
||||||
|
@ -151,7 +157,12 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
is DraggingState -> when (recordingState) {
|
is DraggingState -> when (recordingState) {
|
||||||
is DraggingState.Cancelling -> voiceMessageViews.renderCancelling(recordingState.distanceX)
|
is DraggingState.Cancelling -> voiceMessageViews.renderCancelling(recordingState.distanceX)
|
||||||
is DraggingState.Locking -> voiceMessageViews.renderLocking(recordingState.distanceY)
|
is DraggingState.Locking -> {
|
||||||
|
if (previousState is DraggingState.Cancelling) {
|
||||||
|
voiceMessageViews.showRecordingViews()
|
||||||
|
}
|
||||||
|
voiceMessageViews.renderLocking(recordingState.distanceY)
|
||||||
|
}
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,7 +181,8 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onRecordingTick(milliseconds: Long) {
|
private fun onRecordingTick(milliseconds: Long) {
|
||||||
voiceMessageViews.renderRecordingTimer(callback.currentState(), milliseconds / 1_000)
|
val currentState = lastKnownState ?: return
|
||||||
|
voiceMessageViews.renderRecordingTimer(currentState, milliseconds / 1_000)
|
||||||
val timeDiffToRecordingLimit = BuildConfig.VOICE_MESSAGE_DURATION_LIMIT_MS - milliseconds
|
val timeDiffToRecordingLimit = BuildConfig.VOICE_MESSAGE_DURATION_LIMIT_MS - milliseconds
|
||||||
if (timeDiffToRecordingLimit <= 0) {
|
if (timeDiffToRecordingLimit <= 0) {
|
||||||
post {
|
post {
|
||||||
|
@ -178,7 +190,8 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
} else if (timeDiffToRecordingLimit in 10_000..10_999) {
|
} else if (timeDiffToRecordingLimit in 10_000..10_999) {
|
||||||
post {
|
post {
|
||||||
voiceMessageViews.renderToast(context.getString(R.string.voice_message_n_seconds_warning_toast, floor(timeDiffToRecordingLimit / 1000f).toInt()))
|
val secondsRemaining = floor(timeDiffToRecordingLimit / 1000f).toInt()
|
||||||
|
voiceMessageViews.renderToast(context.getString(R.string.voice_message_n_seconds_warning_toast, secondsRemaining))
|
||||||
vibrate(context)
|
vibrate(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,11 +202,6 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
recordingTicker = null
|
recordingTicker = null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the voice message is recording or is in playback mode
|
|
||||||
*/
|
|
||||||
fun isActive() = callback.currentState() !in listOf(RecordingUiState.None, RecordingUiState.Cancelled)
|
|
||||||
|
|
||||||
override fun onUpdate(state: VoiceMessagePlaybackTracker.Listener.State) {
|
override fun onUpdate(state: VoiceMessagePlaybackTracker.Listener.State) {
|
||||||
when (state) {
|
when (state) {
|
||||||
is VoiceMessagePlaybackTracker.Listener.State.Recording -> {
|
is VoiceMessagePlaybackTracker.Listener.State.Recording -> {
|
||||||
|
|
|
@ -19,7 +19,6 @@ package im.vector.app.features.home.room.detail.composer.voice
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.util.Log
|
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -74,22 +73,17 @@ class VoiceMessageViews(
|
||||||
views.voiceMessageMicButton.setOnTouchListener { _, event ->
|
views.voiceMessageMicButton.setOnTouchListener { _, event ->
|
||||||
when (event.action) {
|
when (event.action) {
|
||||||
MotionEvent.ACTION_DOWN -> {
|
MotionEvent.ACTION_DOWN -> {
|
||||||
Log.e("!!!", "event down: $event")
|
positions.initialize(event)
|
||||||
positions.reset(event)
|
|
||||||
actions.onRequestRecording()
|
actions.onRequestRecording()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
MotionEvent.ACTION_UP -> {
|
MotionEvent.ACTION_UP -> {
|
||||||
actions.onRecordingStopped()
|
actions.onMicButtonReleased()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
MotionEvent.ACTION_MOVE -> {
|
MotionEvent.ACTION_MOVE -> {
|
||||||
if (actions.isActive()) {
|
actions.updateState { currentState -> positions.process(event, currentState) }
|
||||||
actions.updateState { currentState -> positions.process(event, currentState) }
|
true
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
@ -128,6 +122,7 @@ class VoiceMessageViews(
|
||||||
views.voiceMessageLockBackground.isVisible = false
|
views.voiceMessageLockBackground.isVisible = false
|
||||||
views.voiceMessageLockImage.isVisible = false
|
views.voiceMessageLockImage.isVisible = false
|
||||||
views.voiceMessageLockArrow.isVisible = false
|
views.voiceMessageLockArrow.isVisible = false
|
||||||
|
views.voiceMessageSlideToCancelDivider.isVisible = true
|
||||||
// Reset Y translations
|
// Reset Y translations
|
||||||
views.voiceMessageMicButton.translationY = 0F
|
views.voiceMessageMicButton.translationY = 0F
|
||||||
views.voiceMessageLockArrow.translationY = 0F
|
views.voiceMessageLockArrow.translationY = 0F
|
||||||
|
@ -167,11 +162,14 @@ class VoiceMessageViews(
|
||||||
} else {
|
} else {
|
||||||
animateLockImageWithBackground()
|
animateLockImageWithBackground()
|
||||||
}
|
}
|
||||||
|
views.voiceMessageSlideToCancelDivider.isVisible = false
|
||||||
views.voiceMessageLockArrow.isVisible = false
|
views.voiceMessageLockArrow.isVisible = false
|
||||||
views.voiceMessageLockArrow.animate().translationY(0f).start()
|
views.voiceMessageLockArrow.animate().translationY(0f).start()
|
||||||
views.voiceMessageSlideToCancel.isVisible = false
|
views.voiceMessageSlideToCancel.isVisible = false
|
||||||
views.voiceMessageSlideToCancel.animate().translationX(0f).translationY(0f).start()
|
views.voiceMessageSlideToCancel.animate().translationX(0f).translationY(0f).start()
|
||||||
views.voiceMessagePlaybackLayout.isVisible = false
|
views.voiceMessagePlaybackLayout.isVisible = false
|
||||||
|
views.voiceMessageTimerIndicator.isVisible = false
|
||||||
|
views.voiceMessageTimer.isVisible = false
|
||||||
|
|
||||||
if (recordingState != RecordingUiState.Locked) {
|
if (recordingState != RecordingUiState.Locked) {
|
||||||
views.voiceMessageMicButton
|
views.voiceMessageMicButton
|
||||||
|
@ -182,8 +180,6 @@ class VoiceMessageViews(
|
||||||
.translationY(0f)
|
.translationY(0f)
|
||||||
.setDuration(150)
|
.setDuration(150)
|
||||||
.withEndAction {
|
.withEndAction {
|
||||||
views.voiceMessageTimerIndicator.isVisible = false
|
|
||||||
views.voiceMessageTimer.isVisible = false
|
|
||||||
resetMicButtonUi()
|
resetMicButtonUi()
|
||||||
isCancelled?.let {
|
isCancelled?.let {
|
||||||
onVoiceRecordingEnded(it)
|
onVoiceRecordingEnded(it)
|
||||||
|
@ -349,8 +345,7 @@ class VoiceMessageViews(
|
||||||
|
|
||||||
interface Actions {
|
interface Actions {
|
||||||
fun onRequestRecording()
|
fun onRequestRecording()
|
||||||
fun onRecordingStopped()
|
fun onMicButtonReleased()
|
||||||
fun isActive(): Boolean
|
|
||||||
fun updateState(updater: (RecordingUiState) -> RecordingUiState)
|
fun updateState(updater: (RecordingUiState) -> RecordingUiState)
|
||||||
fun sendMessage()
|
fun sendMessage()
|
||||||
fun delete()
|
fun delete()
|
||||||
|
|
|
@ -95,6 +95,7 @@
|
||||||
|
|
||||||
<!-- Slide to cancel text should go under this view -->
|
<!-- Slide to cancel text should go under this view -->
|
||||||
<View
|
<View
|
||||||
|
android:id="@+id/voiceMessageSlideToCancelDivider"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:background="?android:colorBackground"
|
android:background="?android:colorBackground"
|
||||||
|
|
Loading…
Reference in a new issue