From 2ad121e96e6f809ce4b7f1ed07bf72f1509a8d96 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 11 Nov 2021 16:57:06 +0000 Subject: [PATCH] moving the recording ui state to the textcomposer view model and state --- .../home/room/detail/RoomDetailFragment.kt | 24 +++++-------------- .../detail/composer/TextComposerAction.kt | 3 ++- .../detail/composer/TextComposerViewModel.kt | 22 ++++++++--------- .../detail/composer/TextComposerViewState.kt | 15 ++++++++++-- .../composer/voice/DraggableStateProcessor.kt | 10 ++++---- .../voice/VoiceMessageRecorderView.kt | 19 +++++++++------ .../composer/voice/VoiceMessageViews.kt | 2 ++ 7 files changed, 50 insertions(+), 45 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index ba45348cab..844de4c980 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -696,26 +696,14 @@ class RoomDetailFragment @Inject constructor( voiceMessagePlaybackTracker.track(VoiceMessagePlaybackTracker.RECORDING_ID, views.voiceMessageRecorderView) views.voiceMessageRecorderView.callback = object : VoiceMessageRecorderView.Callback { - private var currentUiState: RecordingUiState = RecordingUiState.None - - init { - display(currentUiState) - } - override fun onVoiceRecordingStarted() { if (checkPermissions(PERMISSIONS_FOR_VOICE_MESSAGE, requireActivity(), permissionVoiceMessageLauncher)) { roomDetailViewModel.handle(RoomDetailAction.StartRecordingVoiceMessage) - textComposerViewModel.handle(TextComposerAction.OnVoiceRecordingStateChanged(true)) vibrate(requireContext()) display(RecordingUiState.Started) } } - override fun onVoiceRecordingEnded(isCancelled: Boolean) { - roomDetailViewModel.handle(RoomDetailAction.EndRecordingVoiceMessage(isCancelled)) - textComposerViewModel.handle(TextComposerAction.OnVoiceRecordingStateChanged(false)) - } - override fun onVoiceRecordingPlaybackModeOn() { roomDetailViewModel.handle(RoomDetailAction.PauseRecordingVoiceMessage) } @@ -725,7 +713,8 @@ class RoomDetailFragment @Inject constructor( } override fun onRecordingStopped() { - if (currentUiState != RecordingUiState.Locked) { + roomDetailViewModel.handle(RoomDetailAction.EndRecordingVoiceMessage(isCancelled = true)) + if (currentState() != RecordingUiState.Locked) { display(RecordingUiState.None) } } @@ -739,6 +728,7 @@ class RoomDetailFragment @Inject constructor( } override fun deleteVoiceMessage() { + roomDetailViewModel.handle(RoomDetailAction.EndRecordingVoiceMessage(isCancelled = true)) display(RecordingUiState.Cancelled) } @@ -751,13 +741,10 @@ class RoomDetailFragment @Inject constructor( } private fun display(state: RecordingUiState) { - if (currentUiState != state) { - views.voiceMessageRecorderView.display(state) - } - currentUiState = state + textComposerViewModel.handle(TextComposerAction.OnVoiceRecordingUiStateChanged(state)) } - override fun currentState() = currentUiState + override fun currentState() = withState(textComposerViewModel) { it.voiceRecordingUiState } } } @@ -1444,6 +1431,7 @@ class RoomDetailFragment @Inject constructor( views.composerLayout.isInvisible = !textComposerState.isComposerVisible views.voiceMessageRecorderView.isVisible = textComposerState.isVoiceMessageRecorderVisible views.composerLayout.views.sendButton.isInvisible = !textComposerState.isSendButtonVisible + views.voiceMessageRecorderView.display(textComposerState.voiceRecordingUiState) views.composerLayout.setRoomEncrypted(summary.isEncrypted) // views.composerLayout.alwaysShowSendButton = false if (textComposerState.canSendMessage) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerAction.kt index 7725400187..4f85b78226 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerAction.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerAction.kt @@ -17,6 +17,7 @@ package im.vector.app.features.home.room.detail.composer import im.vector.app.core.platform.VectorViewModelAction +import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView sealed class TextComposerAction : VectorViewModelAction { data class SaveDraft(val draft: String) : TextComposerAction() @@ -27,5 +28,5 @@ sealed class TextComposerAction : VectorViewModelAction { data class EnterRegularMode(val text: String, val fromSharing: Boolean) : TextComposerAction() data class UserIsTyping(val isTyping: Boolean) : TextComposerAction() data class OnTextChanged(val text: CharSequence) : TextComposerAction() - data class OnVoiceRecordingStateChanged(val isRecording: Boolean) : TextComposerAction() + data class OnVoiceRecordingUiStateChanged(val uiState: VoiceMessageRecorderView.RecordingUiState) : TextComposerAction() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt index 66d49f9819..2ff8ef6618 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt @@ -77,20 +77,20 @@ class TextComposerViewModel @AssistedInject constructor( override fun handle(action: TextComposerAction) { Timber.v("Handle action: $action") when (action) { - is TextComposerAction.EnterEditMode -> handleEnterEditMode(action) - is TextComposerAction.EnterQuoteMode -> handleEnterQuoteMode(action) - is TextComposerAction.EnterRegularMode -> handleEnterRegularMode(action) - is TextComposerAction.EnterReplyMode -> handleEnterReplyMode(action) - is TextComposerAction.SaveDraft -> handleSaveDraft(action) - is TextComposerAction.SendMessage -> handleSendMessage(action) - is TextComposerAction.UserIsTyping -> handleUserIsTyping(action) - is TextComposerAction.OnTextChanged -> handleOnTextChanged(action) - is TextComposerAction.OnVoiceRecordingStateChanged -> handleOnVoiceRecordingStateChanged(action) + is TextComposerAction.EnterEditMode -> handleEnterEditMode(action) + is TextComposerAction.EnterQuoteMode -> handleEnterQuoteMode(action) + is TextComposerAction.EnterRegularMode -> handleEnterRegularMode(action) + is TextComposerAction.EnterReplyMode -> handleEnterReplyMode(action) + is TextComposerAction.SaveDraft -> handleSaveDraft(action) + is TextComposerAction.SendMessage -> handleSendMessage(action) + is TextComposerAction.UserIsTyping -> handleUserIsTyping(action) + is TextComposerAction.OnTextChanged -> handleOnTextChanged(action) + is TextComposerAction.OnVoiceRecordingUiStateChanged -> handleOnVoiceRecordingUiStateChanged(action) } } - private fun handleOnVoiceRecordingStateChanged(action: TextComposerAction.OnVoiceRecordingStateChanged) = setState { - copy(isVoiceRecording = action.isRecording) + private fun handleOnVoiceRecordingUiStateChanged(action: TextComposerAction.OnVoiceRecordingUiStateChanged) = setState { + copy(voiceRecordingUiState = action.uiState) } private fun handleOnTextChanged(action: TextComposerAction.OnTextChanged) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewState.kt index 199fb1b82d..99cd4b0e30 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewState.kt @@ -18,6 +18,7 @@ package im.vector.app.features.home.room.detail.composer import com.airbnb.mvrx.MavericksState import im.vector.app.features.home.room.detail.RoomDetailArgs +import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent /** @@ -44,11 +45,21 @@ sealed class SendMode(open val text: String) { data class TextComposerViewState( val roomId: String, val canSendMessage: Boolean = true, - val isVoiceRecording: Boolean = false, val isSendButtonVisible: Boolean = false, - val sendMode: SendMode = SendMode.REGULAR("", false) + val sendMode: SendMode = SendMode.REGULAR("", false), + val voiceRecordingUiState: VoiceMessageRecorderView.RecordingUiState = VoiceMessageRecorderView.RecordingUiState.None ) : MavericksState { + val isVoiceRecording = when (voiceRecordingUiState) { + VoiceMessageRecorderView.RecordingUiState.None, + VoiceMessageRecorderView.RecordingUiState.Cancelled, + VoiceMessageRecorderView.RecordingUiState.Playback -> false + is VoiceMessageRecorderView.DraggingState.Cancelling, + is VoiceMessageRecorderView.DraggingState.Locking, + VoiceMessageRecorderView.RecordingUiState.Locked, + VoiceMessageRecorderView.RecordingUiState.Started -> true + } + val isComposerVisible = canSendMessage && !isVoiceRecording val isVoiceMessageRecorderVisible = canSendMessage && !isSendButtonVisible diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/DraggableStateProcessor.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/DraggableStateProcessor.kt index 5825e60ecf..41c9f83a97 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/DraggableStateProcessor.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/DraggableStateProcessor.kt @@ -77,12 +77,10 @@ class DraggableStateProcessor( } is DraggingState.Cancelling -> { // Check if cancelling conditions met, also check if it should be initial state - if (distanceX < minimumMove && distanceX < lastDistanceX) { - RecordingUiState.Started - } else if (shouldCancelRecording(distanceX)) { - RecordingUiState.Cancelled - } else { - DraggingState.Cancelling(distanceX) + when { + distanceX < minimumMove && distanceX < lastDistanceX -> RecordingUiState.Started + shouldCancelRecording(distanceX) -> RecordingUiState.Cancelled + else -> DraggingState.Cancelling(distanceX) } } is DraggingState.Locking -> { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageRecorderView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageRecorderView.kt index 2227405507..8c3eadca1c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageRecorderView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageRecorderView.kt @@ -41,7 +41,6 @@ class VoiceMessageRecorderView @JvmOverloads constructor( interface Callback { fun onVoiceRecordingStarted() - fun onVoiceRecordingEnded(isCancelled: Boolean) fun onVoiceRecordingPlaybackModeOn() fun onVoicePlaybackButtonClicked() fun onRecordingStopped() @@ -59,6 +58,7 @@ class VoiceMessageRecorderView @JvmOverloads constructor( lateinit var callback: Callback private var recordingTicker: CountUpTimer? = null + private var lastKnownState: RecordingUiState? = null init { inflate(this.context, R.layout.view_voice_message_recorder, this) @@ -92,8 +92,11 @@ class VoiceMessageRecorderView @JvmOverloads constructor( override fun isActive() = callback.currentState() != RecordingUiState.Cancelled override fun updateState(updater: (RecordingUiState) -> RecordingUiState) { - updater(callback.currentState()).also { newState -> - callback.onUiStateChanged(newState) + updater(lastKnownState ?: RecordingUiState.None).also { newState -> + when (newState) { + is DraggingState -> display(newState) + else -> callback.onUiStateChanged(newState) + } } } @@ -102,7 +105,6 @@ class VoiceMessageRecorderView @JvmOverloads constructor( } override fun delete() { - // this was previously marked as cancelled true callback.deleteVoiceMessage() } @@ -117,11 +119,12 @@ class VoiceMessageRecorderView @JvmOverloads constructor( } fun display(recordingState: RecordingUiState) { + if (lastKnownState == recordingState) return + lastKnownState = recordingState when (recordingState) { RecordingUiState.None -> { stopRecordingTicker() voiceMessageViews.initViews() - callback.onVoiceRecordingEnded(false) } RecordingUiState.Started -> { startRecordingTicker() @@ -130,13 +133,15 @@ class VoiceMessageRecorderView @JvmOverloads constructor( } RecordingUiState.Cancelled -> { stopRecordingTicker() - voiceMessageViews.hideRecordingViews(recordingState, isCancelled = true) { callback.onVoiceRecordingEnded(it) } + voiceMessageViews.hideRecordingViews(recordingState, isCancelled = true) { callback.deleteVoiceMessage() } vibrate(context) } RecordingUiState.Locked -> { voiceMessageViews.renderLocked() postDelayed({ - voiceMessageViews.showRecordingLockedViews(recordingState) { callback.onVoiceRecordingEnded(it) } + voiceMessageViews.showRecordingLockedViews(recordingState) { + // do nothing + } }, 500) } RecordingUiState.Playback -> { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageViews.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageViews.kt index 63b5dc17ee..938ae74983 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageViews.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/voice/VoiceMessageViews.kt @@ -19,6 +19,7 @@ package im.vector.app.features.home.room.detail.composer.voice import android.annotation.SuppressLint import android.content.res.Resources import android.text.format.DateUtils +import android.util.Log import android.view.MotionEvent import android.view.View import android.view.ViewGroup @@ -73,6 +74,7 @@ class VoiceMessageViews( views.voiceMessageMicButton.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { + Log.e("!!!", "event down: $event") positions.reset(event) actions.onRequestRecording() true