From a2583a406dbad8a7e2ba70064ba65d826534e9fd Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Fri, 14 Jun 2024 09:14:26 -0400 Subject: [PATCH 1/6] Add fun for ending the recording session --- .../main/java/org/wordpress/android/util/audio/IAudioRecorder.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/WordPress/src/main/java/org/wordpress/android/util/audio/IAudioRecorder.kt b/WordPress/src/main/java/org/wordpress/android/util/audio/IAudioRecorder.kt index 73ab0ca30725..78cbd55efbad 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/audio/IAudioRecorder.kt +++ b/WordPress/src/main/java/org/wordpress/android/util/audio/IAudioRecorder.kt @@ -9,6 +9,7 @@ interface IAudioRecorder { fun pauseRecording() fun resumeRecording() fun recordingUpdates(): Flow + fun endRecordingSession() sealed class AudioRecorderResult { data class Success(val recordingPath: String) : AudioRecorderResult() From 7e71d71873c8ce22864a25ddb9e24164864f4258 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Fri, 14 Jun 2024 09:14:37 -0400 Subject: [PATCH 2/6] Add fun for ending the recording session --- .../wordpress/android/ui/voicetocontent/RecordingUseCase.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/RecordingUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/RecordingUseCase.kt index 3552ea314fe2..069d10464522 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/RecordingUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/RecordingUseCase.kt @@ -14,7 +14,6 @@ class RecordingUseCase @Inject constructor( audioRecorder.startRecording(onRecordingFinished) } - @Suppress("ReturnCount") fun stopRecording() { audioRecorder.stopRecording() } @@ -22,5 +21,8 @@ class RecordingUseCase @Inject constructor( fun recordingUpdates(): Flow { return audioRecorder.recordingUpdates() } -} + fun endRecordingSession() { + audioRecorder.endRecordingSession() + } +} From 280e1563a10d117e592171e28fafc518360a233a Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Fri, 14 Jun 2024 09:15:33 -0400 Subject: [PATCH 3/6] Implement endRecordingSession so that the recording resources can be released outside of a stop recording action --- .../wordpress/android/util/audio/AudioRecorder.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/util/audio/AudioRecorder.kt b/WordPress/src/main/java/org/wordpress/android/util/audio/AudioRecorder.kt index 73f957289151..12c0a01b2f65 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/audio/AudioRecorder.kt +++ b/WordPress/src/main/java/org/wordpress/android/util/audio/AudioRecorder.kt @@ -90,7 +90,7 @@ class AudioRecorder( } } - override fun stopRecording() { + private fun clearResources() { try { recorder?.apply { stop() @@ -104,7 +104,11 @@ class AudioRecorder( _isPaused.value = false _isRecording.value = false } - // return filePath + } + + override fun stopRecording() { + clearResources() + // return the filePath onRecordingFinished(Success(filePath)) } @@ -136,6 +140,10 @@ class AudioRecorder( } } + override fun endRecordingSession() { + clearResources() + } + override fun recordingUpdates(): Flow = recordingUpdates @Suppress("MagicNumber") From e9ffc3ee69ace248d0aa100266d65109cb2adcad Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Fri, 14 Jun 2024 09:17:25 -0400 Subject: [PATCH 4/6] Invoke endRecordingSession when the bottom sheet is closed via swipe/x or the stop button is tapped --- .../android/ui/voicetocontent/VoiceToContentViewModel.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentViewModel.kt index 6bb4264b368a..dc57bde0b915 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentViewModel.kt @@ -104,6 +104,10 @@ class VoiceToContentViewModel @Inject constructor( isStarted = true } + fun onBottomSheetClosed() { + recordingUseCase.endRecordingSession() + } + // Recording private fun updateRecordingData(recordingUpdate: RecordingUpdate) { _recordingUpdate.value = recordingUpdate @@ -206,6 +210,7 @@ class VoiceToContentViewModel @Inject constructor( private fun onClose() { logger.track(Stat.VOICE_TO_CONTENT_BUTTON_CLOSE_TAPPED) + recordingUseCase.endRecordingSession() _dismiss.postValue(Unit) } From fc7a0fb67e3d40b3216c6c602578cc003a6e722e Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Fri, 14 Jun 2024 09:17:58 -0400 Subject: [PATCH 5/6] Add listener for when bottom sheet is closing --- .../VoiceToContentDialogFragment.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentDialogFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentDialogFragment.kt index ff491318e2bc..5fdd8d1aa90c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentDialogFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentDialogFragment.kt @@ -64,6 +64,27 @@ class VoiceToContentDialogFragment : BottomSheetDialogFragment() { behavior.skipCollapsed = true behavior.state = BottomSheetBehavior.STATE_EXPANDED + behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { + @SuppressLint("SwitchIntDef") + override fun onStateChanged(bottomSheet: View, newState: Int) { + when (newState) { + BottomSheetBehavior.STATE_HIDDEN -> { + // Bottom sheet is hidden, you can listen for this event here + viewModel.onBottomSheetClosed() + } + BottomSheetBehavior.STATE_COLLAPSED -> { + // Bottom sheet is collapsed, you can listen for this event here + viewModel.onBottomSheetClosed() + } + // Handle other states if necessary + } + } + + override fun onSlide(bottomSheet: View, slideOffset: Float) { + // Handle the slide offset if needed + } + }) + // Disable touch interception by the bottom sheet to allow nested scrolling bottomSheet.setOnTouchListener { _, _ -> false } } From 9aa4aec2b5f3cdd617da32d95f71ca44cb0ac792 Mon Sep 17 00:00:00 2001 From: Annmarie Ziegler Date: Fri, 14 Jun 2024 14:06:22 -0400 Subject: [PATCH 6/6] Handle closing the bottom sheet on outside touch dynamically --- .../VoiceToContentDialogFragment.kt | 27 ++++++++++++++----- .../voicetocontent/VoiceToContentViewModel.kt | 8 ++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentDialogFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentDialogFragment.kt index 5fdd8d1aa90c..7375ae03ffc2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentDialogFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentDialogFragment.kt @@ -2,6 +2,7 @@ package org.wordpress.android.ui.voicetocontent import android.annotation.SuppressLint import android.app.Dialog +import android.content.DialogInterface import android.content.Intent import android.net.Uri import android.os.Bundle @@ -18,6 +19,7 @@ import org.wordpress.android.ui.compose.theme.AppTheme import org.wordpress.android.R import org.wordpress.android.util.audio.IAudioRecorder.Companion.REQUIRED_RECORDING_PERMISSIONS import android.provider.Settings +import android.util.Log import android.widget.FrameLayout import androidx.compose.material.ExperimentalMaterialApi import com.google.android.material.bottomsheet.BottomSheetBehavior @@ -68,15 +70,10 @@ class VoiceToContentDialogFragment : BottomSheetDialogFragment() { @SuppressLint("SwitchIntDef") override fun onStateChanged(bottomSheet: View, newState: Int) { when (newState) { - BottomSheetBehavior.STATE_HIDDEN -> { - // Bottom sheet is hidden, you can listen for this event here - viewModel.onBottomSheetClosed() - } + BottomSheetBehavior.STATE_HIDDEN, BottomSheetBehavior.STATE_COLLAPSED -> { - // Bottom sheet is collapsed, you can listen for this event here - viewModel.onBottomSheetClosed() + onBottomSheetClosed() } - // Handle other states if necessary } } @@ -88,9 +85,25 @@ class VoiceToContentDialogFragment : BottomSheetDialogFragment() { // Disable touch interception by the bottom sheet to allow nested scrolling bottomSheet.setOnTouchListener { _, _ -> false } } + + // Observe the ViewModel to update the cancelable state of closing on outside touch + viewModel.isCancelableOutsideTouch.observe(this) { cancelable -> + Log.i(javaClass.simpleName, "***=> disable outside touch") + dialog.setCanceledOnTouchOutside(cancelable) + } + return dialog } + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + viewModel.onBottomSheetClosed() + } + + private fun onBottomSheetClosed() { + dismiss() + } + private fun observeViewModel() { viewModel.requestPermission.observe(viewLifecycleOwner) { requestAllPermissionsForRecording() diff --git a/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentViewModel.kt index dc57bde0b915..9e99790777ae 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/voicetocontent/VoiceToContentViewModel.kt @@ -56,6 +56,9 @@ class VoiceToContentViewModel @Inject constructor( private val _onIneligibleForVoiceToContent = MutableLiveData() val onIneligibleForVoiceToContent = _onIneligibleForVoiceToContent as LiveData + private val _isCancelableOutsideTouch = MutableLiveData(true) + val isCancelableOutsideTouch: LiveData get() = _isCancelableOutsideTouch + private var isStarted = false private val _state = MutableStateFlow(VoiceToContentUiState( @@ -129,6 +132,7 @@ class VoiceToContentViewModel @Inject constructor( private fun startRecording() { transitionToRecording() + disableDialogCancelableOutsideTouch() recordingUseCase.startRecording { audioRecorderResult -> when (audioRecorderResult) { is Success -> { @@ -147,6 +151,10 @@ class VoiceToContentViewModel @Inject constructor( } } + private fun disableDialogCancelableOutsideTouch() { + _isCancelableOutsideTouch.value = false + } + @Suppress("ReturnCount") private fun getRecordingFile(recordingPath: String): File? { if (recordingPath.isEmpty()) return null