avoiding stopping any active recording if we're rotating

- had to keep track of the recording start time in order to maintain the current length counter
This commit is contained in:
Adam Brown 2021-11-24 14:23:33 +00:00
parent bbb3a6139f
commit 4a5e21ad21
4 changed files with 37 additions and 27 deletions

View File

@ -699,7 +699,7 @@ class RoomDetailFragment @Inject constructor(
if (checkPermissions(PERMISSIONS_FOR_VOICE_MESSAGE, requireActivity(), permissionVoiceMessageLauncher)) {
messageComposerViewModel.handle(MessageComposerAction.StartRecordingVoiceMessage)
vibrate(requireContext())
updateRecordingUiState(RecordingUiState.Started)
updateRecordingUiState(RecordingUiState.Started(System.currentTimeMillis()))
}
}
@ -713,7 +713,9 @@ class RoomDetailFragment @Inject constructor(
}
override fun onVoiceRecordingLocked() {
updateRecordingUiState(RecordingUiState.Locked)
val startedState = withState(messageComposerViewModel) { it.voiceRecordingUiState as? RecordingUiState.Started }
val startTime = startedState?.recordingStartTimestamp ?: System.currentTimeMillis()
updateRecordingUiState(RecordingUiState.Locked(startTime))
}
override fun onVoiceRecordingEnded() {
@ -1131,11 +1133,15 @@ class RoomDetailFragment @Inject constructor(
super.onPause()
notificationDrawerManager.setCurrentRoom(null)
voiceMessagePlaybackTracker.unTrack(VoiceMessagePlaybackTracker.RECORDING_ID)
messageComposerViewModel.handle(MessageComposerAction.SaveDraft(views.composerLayout.text.toString()))
// We should improve the UX to support going into playback mode when paused and delete the media when the view is destroyed.
messageComposerViewModel.handle(MessageComposerAction.EndAllVoiceActions(deleteRecord = false))
views.voiceMessageRecorderView.render(RecordingUiState.None)
if (withState(messageComposerViewModel) { it.isVoiceRecording } && requireActivity().isChangingConfigurations) {
// we're rotating, maintain any active recordings
} else {
messageComposerViewModel.handle(MessageComposerAction.SaveDraft(views.composerLayout.text.toString()))
// We should improve the UX to support going into playback mode when paused and delete the media when the view is destroyed.
messageComposerViewModel.handle(MessageComposerAction.EndAllVoiceActions(deleteRecord = false))
views.voiceMessageRecorderView.render(RecordingUiState.None)
}
}
private val attachmentFileActivityResultLauncher = registerStartForActivityResult {

View File

@ -54,8 +54,8 @@ data class MessageComposerViewState(
VoiceMessageRecorderView.RecordingUiState.None,
VoiceMessageRecorderView.RecordingUiState.Cancelled,
VoiceMessageRecorderView.RecordingUiState.Playback -> false
VoiceMessageRecorderView.RecordingUiState.Locked,
VoiceMessageRecorderView.RecordingUiState.Started -> true
is VoiceMessageRecorderView.RecordingUiState.Locked,
is VoiceMessageRecorderView.RecordingUiState.Started -> true
}
val isVoiceMessageIdle = !isVoiceRecording

View File

@ -105,32 +105,35 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
fun render(recordingState: RecordingUiState) {
if (lastKnownState == recordingState) return
lastKnownState = recordingState
when (recordingState) {
RecordingUiState.None -> {
RecordingUiState.None -> {
reset()
}
RecordingUiState.Started -> {
startRecordingTicker()
is RecordingUiState.Started -> {
startRecordingTicker(startFromLocked = false, startAt = recordingState.recordingStartTimestamp)
voiceMessageViews.renderToast(context.getString(R.string.voice_message_release_to_send_toast))
voiceMessageViews.showRecordingViews()
dragState = DraggingState.Ready
}
RecordingUiState.Cancelled -> {
RecordingUiState.Cancelled -> {
reset()
vibrate(context)
}
RecordingUiState.Locked -> {
is RecordingUiState.Locked -> {
if (lastKnownState == null) {
startRecordingTicker(startFromLocked = true, startAt = recordingState.recordingStartTimestamp)
}
voiceMessageViews.renderLocked()
postDelayed({
voiceMessageViews.showRecordingLockedViews(recordingState)
}, 500)
}
RecordingUiState.Playback -> {
RecordingUiState.Playback -> {
stopRecordingTicker()
voiceMessageViews.showPlaybackViews()
}
}
lastKnownState = recordingState
}
private fun reset() {
@ -159,22 +162,23 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
dragState = newDragState
}
private fun startRecordingTicker() {
private fun startRecordingTicker(startFromLocked: Boolean, startAt: Long) {
val startMs = ((System.currentTimeMillis() - startAt)).coerceAtLeast(0)
recordingTicker?.stop()
recordingTicker = CountUpTimer().apply {
tickListener = object : CountUpTimer.TickListener {
override fun onTick(milliseconds: Long) {
onRecordingTick(milliseconds)
val isLocked = startFromLocked || lastKnownState is RecordingUiState.Locked
onRecordingTick(isLocked, milliseconds + startMs)
}
}
resume()
}
onRecordingTick(0L)
onRecordingTick(startFromLocked, milliseconds = startMs)
}
private fun onRecordingTick(milliseconds: Long) {
val currentState = lastKnownState ?: return
voiceMessageViews.renderRecordingTimer(currentState, milliseconds / 1_000)
private fun onRecordingTick(isLocked: Boolean, milliseconds: Long) {
voiceMessageViews.renderRecordingTimer(isLocked, milliseconds / 1_000)
val timeDiffToRecordingLimit = BuildConfig.VOICE_MESSAGE_DURATION_LIMIT_MS - milliseconds
if (timeDiffToRecordingLimit <= 0) {
post {
@ -211,9 +215,9 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
sealed interface RecordingUiState {
object None : RecordingUiState
object Started : RecordingUiState
data class Started(val recordingStartTimestamp: Long) : RecordingUiState
object Cancelled : RecordingUiState
object Locked : RecordingUiState
data class Locked(val recordingStartTimestamp: Long) : RecordingUiState
object Playback : RecordingUiState
}

View File

@ -154,7 +154,7 @@ class VoiceMessageViews(
fun hideRecordingViews(recordingState: RecordingUiState) {
// We need to animate the lock image first
if (recordingState != RecordingUiState.Locked) {
if (recordingState !is RecordingUiState.Locked) {
views.voiceMessageLockImage.isVisible = false
views.voiceMessageLockImage.animate().translationY(0f).start()
views.voiceMessageLockBackground.isVisible = false
@ -171,7 +171,7 @@ class VoiceMessageViews(
views.voiceMessageTimerIndicator.isVisible = false
views.voiceMessageTimer.isVisible = false
if (recordingState != RecordingUiState.Locked) {
if (recordingState !is RecordingUiState.Locked) {
views.voiceMessageMicButton
.animate()
.scaleX(1f)
@ -304,9 +304,9 @@ class VoiceMessageViews(
views.voiceMessageToast.isVisible = false
}
fun renderRecordingTimer(recordingState: RecordingUiState, recordingTimeMillis: Long) {
fun renderRecordingTimer(isLocked: Boolean, recordingTimeMillis: Long) {
val formattedTimerText = DateUtils.formatElapsedTime(recordingTimeMillis)
if (recordingState == RecordingUiState.Locked) {
if (isLocked) {
views.voicePlaybackTime.apply {
post {
text = formattedTimerText