Design review fixes.
This commit is contained in:
parent
a9beded589
commit
3372177b0e
|
@ -84,6 +84,7 @@ import im.vector.app.core.extensions.showKeyboard
|
||||||
import im.vector.app.core.extensions.trackItemsVisibilityChange
|
import im.vector.app.core.extensions.trackItemsVisibilityChange
|
||||||
import im.vector.app.core.glide.GlideApp
|
import im.vector.app.core.glide.GlideApp
|
||||||
import im.vector.app.core.glide.GlideRequests
|
import im.vector.app.core.glide.GlideRequests
|
||||||
|
import im.vector.app.core.hardware.vibrate
|
||||||
import im.vector.app.core.intent.getFilenameFromUri
|
import im.vector.app.core.intent.getFilenameFromUri
|
||||||
import im.vector.app.core.intent.getMimeTypeFromUri
|
import im.vector.app.core.intent.getMimeTypeFromUri
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
@ -599,6 +600,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
views.composerLayout.isInvisible = true
|
views.composerLayout.isInvisible = true
|
||||||
roomDetailViewModel.handle(RoomDetailAction.StartRecordingVoiceMessage)
|
roomDetailViewModel.handle(RoomDetailAction.StartRecordingVoiceMessage)
|
||||||
context?.toast(R.string.voice_message_release_to_send_toast)
|
context?.toast(R.string.voice_message_release_to_send_toast)
|
||||||
|
vibrate(requireContext())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import androidx.core.view.isVisible
|
||||||
import com.visualizer.amplitude.AudioRecordView
|
import com.visualizer.amplitude.AudioRecordView
|
||||||
import im.vector.app.BuildConfig
|
import im.vector.app.BuildConfig
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.hardware.vibrate
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
import im.vector.app.databinding.ViewVoiceMessageRecorderBinding
|
import im.vector.app.databinding.ViewVoiceMessageRecorderBinding
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlaybackTracker
|
import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlaybackTracker
|
||||||
|
@ -37,6 +38,7 @@ import timber.log.Timber
|
||||||
import java.util.Timer
|
import java.util.Timer
|
||||||
import java.util.TimerTask
|
import java.util.TimerTask
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.floor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the voice message recording view and animations.
|
* Encapsulates the voice message recording view and animations.
|
||||||
|
@ -152,13 +154,15 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
private fun handleMoveAction(event: MotionEvent) {
|
private fun handleMoveAction(event: MotionEvent) {
|
||||||
val currentX = event.rawX
|
val currentX = event.rawX
|
||||||
val currentY = event.rawY
|
val currentY = event.rawY
|
||||||
updateRecordingState(currentX, currentY)
|
|
||||||
|
val isRecordingStateChanged = updateRecordingState(currentX, currentY)
|
||||||
|
|
||||||
when (recordingState) {
|
when (recordingState) {
|
||||||
RecordingState.CANCELLING -> {
|
RecordingState.CANCELLING -> {
|
||||||
val translationAmount = currentX - firstX
|
val translationAmount = currentX - firstX
|
||||||
views.voiceMessageMicButton.translationX = translationAmount
|
views.voiceMessageMicButton.translationX = translationAmount
|
||||||
views.voiceMessageSlideToCancel.translationX = translationAmount
|
views.voiceMessageSlideToCancel.translationX = translationAmount
|
||||||
|
views.voiceMessageSlideToCancel.alpha = 1 - abs(translationAmount) / ((firstX - views.voiceMessageTimer.x) / 3)
|
||||||
views.voiceMessageLockBackground.isVisible = false
|
views.voiceMessageLockBackground.isVisible = false
|
||||||
views.voiceMessageLockImage.isVisible = false
|
views.voiceMessageLockImage.isVisible = false
|
||||||
views.voiceMessageLockArrow.isVisible = false
|
views.voiceMessageLockArrow.isVisible = false
|
||||||
|
@ -174,10 +178,12 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
hideRecordingViews()
|
hideRecordingViews()
|
||||||
}
|
}
|
||||||
RecordingState.LOCKED -> {
|
RecordingState.LOCKED -> {
|
||||||
views.voiceMessageLockImage.setImageResource(R.drawable.ic_voice_message_locked)
|
if (isRecordingStateChanged) { // Do not update views if it was already in locked state.
|
||||||
views.voiceMessageLockImage.postDelayed({
|
views.voiceMessageLockImage.setImageResource(R.drawable.ic_voice_message_locked)
|
||||||
showRecordingLockedViews()
|
views.voiceMessageLockImage.postDelayed({
|
||||||
}, 500)
|
showRecordingLockedViews()
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RecordingState.STARTED -> {
|
RecordingState.STARTED -> {
|
||||||
showRecordingViews()
|
showRecordingViews()
|
||||||
|
@ -189,7 +195,8 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
lastY = currentY
|
lastY = currentY
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateRecordingState(currentX: Float, currentY: Float) {
|
private fun updateRecordingState(currentX: Float, currentY: Float): Boolean {
|
||||||
|
val previousRecordingState = recordingState
|
||||||
val distanceX = abs(firstX - currentX)
|
val distanceX = abs(firstX - currentX)
|
||||||
val distanceY = abs(firstY - currentY)
|
val distanceY = abs(firstY - currentY)
|
||||||
if (recordingState == RecordingState.STARTED) { // Determine if cancelling or locking for the first move action.
|
if (recordingState == RecordingState.STARTED) { // Determine if cancelling or locking for the first move action.
|
||||||
|
@ -211,10 +218,12 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
recordingState = RecordingState.LOCKED
|
recordingState = RecordingState.LOCKED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return previousRecordingState != recordingState
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldCancelRecording(): Boolean {
|
private fun shouldCancelRecording(): Boolean {
|
||||||
return abs(views.voiceMessageTimer.x + views.voiceMessageTimer.width - views.voiceMessageSlideToCancel.x) < 10
|
return abs(views.voiceMessageTimer.x + views.voiceMessageTimer.width - views.voiceMessageSlideToCancel.x) < 10
|
||||||
|
|| views.voiceMessageSlideToCancel.x <= views.voiceMessageTimer.x + views.voiceMessageTimer.width // To handle super fast moving
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldLockRecording(): Boolean {
|
private fun shouldLockRecording(): Boolean {
|
||||||
|
@ -230,15 +239,14 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
val timeDiffToRecordingLimit = BuildConfig.VOICE_MESSAGE_DURATION_LIMIT_MS - recordingTime * 1000
|
val timeDiffToRecordingLimit = BuildConfig.VOICE_MESSAGE_DURATION_LIMIT_MS - recordingTime * 1000
|
||||||
if (timeDiffToRecordingLimit <= 0) {
|
if (timeDiffToRecordingLimit <= 0) {
|
||||||
views.voiceMessageRecordingLayout.post {
|
views.voiceMessageRecordingLayout.post {
|
||||||
callback?.onVoiceRecordingEnded(false)
|
recordingState = RecordingState.PLAYBACK
|
||||||
recordingState = RecordingState.NONE
|
showPlaybackViews()
|
||||||
stopRecordingTimer()
|
stopRecordingTimer()
|
||||||
hideRecordingViews(animationDuration = 0)
|
|
||||||
}
|
}
|
||||||
} else if (timeDiffToRecordingLimit in 10000..11000) {
|
} else if (timeDiffToRecordingLimit in 10000..10999) {
|
||||||
views.voiceMessageRecordingLayout.post {
|
views.voiceMessageRecordingLayout.post {
|
||||||
views.voiceMessageSendButton.isVisible = false
|
context.toast(context.getString(R.string.voice_message_n_seconds_warning_toast, floor(timeDiffToRecordingLimit / 1000f).toInt()))
|
||||||
context.toast(context.getString(R.string.voice_message_n_seconds_warning_toast, (timeDiffToRecordingLimit / 1000).toInt()))
|
vibrate(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,12 +298,13 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
views.voiceMessageSlideToCancel.isVisible = true
|
views.voiceMessageSlideToCancel.isVisible = true
|
||||||
views.voiceMessageTimerIndicator.isVisible = true
|
views.voiceMessageTimerIndicator.isVisible = true
|
||||||
views.voiceMessageTimer.isVisible = true
|
views.voiceMessageTimer.isVisible = true
|
||||||
|
views.voiceMessageSlideToCancel.alpha = 1f
|
||||||
views.voiceMessageSendButton.isVisible = false
|
views.voiceMessageSendButton.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hideRecordingViews(animationDuration: Int = 300) {
|
fun hideRecordingViews(animationDuration: Int = 300) {
|
||||||
views.voiceMessageMicButton.setImageResource(R.drawable.ic_voice_mic)
|
views.voiceMessageMicButton.setImageResource(R.drawable.ic_voice_mic)
|
||||||
views.voiceMessageMicButton.animate().translationX(0f).translationY(0f).setDuration(animationDuration.toLong()).start()
|
views.voiceMessageMicButton.animate().translationX(0f).translationY(0f).setDuration(animationDuration.toLong()).setDuration(0).start()
|
||||||
(views.voiceMessageMicButton.layoutParams as MarginLayoutParams).apply { setMargins(0, 0, dpToPx(12).toInt(), dpToPx(12).toInt()) }
|
(views.voiceMessageMicButton.layoutParams as MarginLayoutParams).apply { setMargins(0, 0, dpToPx(12).toInt(), dpToPx(12).toInt()) }
|
||||||
views.voiceMessageLockBackground.isVisible = false
|
views.voiceMessageLockBackground.isVisible = false
|
||||||
views.voiceMessageLockBackground.animate().translationY(dpToPx(0)).start()
|
views.voiceMessageLockBackground.animate().translationY(dpToPx(0)).start()
|
||||||
|
@ -316,6 +325,7 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
|
||||||
views.voiceMessagePlaybackLayout.findViewById<ImageView>(R.id.voiceMessagePlaybackTimerIndicator).isVisible = true
|
views.voiceMessagePlaybackLayout.findViewById<ImageView>(R.id.voiceMessagePlaybackTimerIndicator).isVisible = true
|
||||||
views.voiceMessagePlaybackLayout.findViewById<ImageView>(R.id.voicePlaybackControlButton).isVisible = false
|
views.voiceMessagePlaybackLayout.findViewById<ImageView>(R.id.voicePlaybackControlButton).isVisible = false
|
||||||
views.voiceMessageSendButton.isVisible = true
|
views.voiceMessageSendButton.isVisible = true
|
||||||
|
context.toast(R.string.voice_message_tap_to_stop_toast)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showPlaybackViews() {
|
private fun showPlaybackViews() {
|
||||||
|
|
|
@ -3416,8 +3416,9 @@
|
||||||
<string name="a11y_pause_voice_message">Pause Voice Message</string>
|
<string name="a11y_pause_voice_message">Pause Voice Message</string>
|
||||||
<string name="a11y_recording_voice_message">Recording voice message</string>
|
<string name="a11y_recording_voice_message">Recording voice message</string>
|
||||||
<string name="a11y_delete_recorded_voice_message">Delete recorded voice message</string>
|
<string name="a11y_delete_recorded_voice_message">Delete recorded voice message</string>
|
||||||
<string name="voice_message_release_to_send_toast">Release to send</string>
|
<string name="voice_message_release_to_send_toast">Hold to record, release to send</string>
|
||||||
<string name="voice_message_n_seconds_warning_toast">%1$ds left</string>
|
<string name="voice_message_n_seconds_warning_toast">%1$ds left</string>
|
||||||
<string name="voice_message_tap_on_waveform_to_stop_toast">Tap on the waveform to stop and playback</string>
|
<string name="voice_message_tap_on_waveform_to_stop_toast">Tap on the waveform to stop and playback</string>
|
||||||
<string name="labs_use_voice_message">Enable voice message</string>
|
<string name="labs_use_voice_message">Enable voice message</string>
|
||||||
|
<string name="voice_message_tap_to_stop_toast">Tap on the wavelength to stop and playback</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue