Skip to content

Commit

Permalink
feat: audio message filter (WPB-6406) (#2835)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandreferris authored Mar 28, 2024
1 parent 7898006 commit 23177ba
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class GlobalDataStore @Inject constructor(@ApplicationContext private val contex
private val APP_LOCK_SOURCE = intPreferencesKey("app_lock_source")

val APP_THEME_OPTION = stringPreferencesKey("app_theme_option")
val RECORD_AUDIO_EFFECTS_CHECKBOX = booleanPreferencesKey("record_audio_effects_checkbox")

private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = PREFERENCES_NAME)

private fun userMigrationStatusKey(userId: String): Preferences.Key<Int> =
Expand Down Expand Up @@ -95,6 +97,13 @@ class GlobalDataStore @Inject constructor(@ApplicationContext private val contex
context.dataStore.edit { it[IS_LOGGING_ENABLED] = enabled }
}

fun isRecordAudioEffectsCheckboxEnabled(): Flow<Boolean> =
getBooleanPreference(RECORD_AUDIO_EFFECTS_CHECKBOX, false)

suspend fun setRecordAudioEffectsCheckboxEnabled(enabled: Boolean) {
context.dataStore.edit { it[RECORD_AUDIO_EFFECTS_CHECKBOX] = enabled }
}

fun isEncryptedProteusStorageEnabled(): Flow<Boolean> =
getBooleanPreference(
IS_ENCRYPTED_PROTEUS_STORAGE_ENABLED,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ class AudioMediaRecorder @Inject constructor(

private var mediaRecorder: MediaRecorder? = null

var outputFile: File? = null
var originalOutputFile: File? = null
var effectsOutputFile: File? = null

private val _maxFileSizeReached = MutableSharedFlow<RecordAudioDialogState>()
fun getMaxFileSizeReached(): Flow<RecordAudioDialogState> =
Expand All @@ -63,18 +64,22 @@ class AudioMediaRecorder @Inject constructor(
MediaRecorder()
}

outputFile = kaliumFileSystem
originalOutputFile = kaliumFileSystem
.tempFilePath(getRecordingAudioFileName())
.toFile()

effectsOutputFile = kaliumFileSystem
.tempFilePath(getRecordingAudioEffectsFileName())
.toFile()

mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder?.setAudioSamplingRate(SAMPLING_RATE)
mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mediaRecorder?.setAudioChannels(AUDIO_CHANNELS)
mediaRecorder?.setAudioEncodingBitRate(AUDIO_ENCONDING_BIT_RATE)
mediaRecorder?.setMaxFileSize(assetLimitInMegabyte)
mediaRecorder?.setOutputFile(outputFile)
mediaRecorder?.setOutputFile(originalOutputFile)

observeAudioFileSize(assetLimitInMegabyte)
}
Expand Down Expand Up @@ -119,6 +124,8 @@ class AudioMediaRecorder @Inject constructor(
private companion object {
fun getRecordingAudioFileName(): String =
"wire-audio-${DateTimeUtil.currentInstant().audioFileDateTime()}.m4a"
fun getRecordingAudioEffectsFileName(): String =
"wire-audio-${DateTimeUtil.currentInstant().audioFileDateTime()}-filter.m4a"
const val SIZE_OF_1MB = 1024 * 1024
const val AUDIO_CHANNELS = 1
const val SAMPLING_RATE = 44100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import android.view.WindowManager
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Checkbox
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
Expand Down Expand Up @@ -81,6 +83,8 @@ fun RecordAudioButtonClose(

@Composable
fun RecordAudioButtonEnabled(
applyAudioFilterState: Boolean,
applyAudioFilterClick: (Boolean) -> Unit,
onClick: () -> Unit,
modifier: Modifier
) {
Expand All @@ -91,12 +95,16 @@ fun RecordAudioButtonEnabled(
iconResId = R.drawable.ic_microphone_on,
contentDescription = R.string.content_description_record_audio_button_start,
buttonColor = colorsScheme().recordAudioStartColor,
bottomText = R.string.record_audio_start_label
bottomText = R.string.record_audio_start_label,
applyAudioFilterState = applyAudioFilterState,
applyAudioFilterClick = applyAudioFilterClick,
isAudioFilterEnabled = true
)
}

@Composable
fun RecordAudioButtonRecording(
applyAudioFilterState: Boolean,
onClick: () -> Unit,
modifier: Modifier
) {
Expand Down Expand Up @@ -135,12 +143,15 @@ fun RecordAudioButtonRecording(
contentDescription = R.string.content_description_record_audio_button_stop,
buttonColor = colorsScheme().recordAudioStopColor,
bottomText = R.string.record_audio_recording_label,
buttonState = if (seconds > 0) WireButtonState.Default else WireButtonState.Disabled
buttonState = if (seconds > 0) WireButtonState.Default else WireButtonState.Disabled,
applyAudioFilterState = applyAudioFilterState,
applyAudioFilterClick = { }
)
}

@Composable
fun RecordAudioButtonSend(
applyAudioFilterState: Boolean,
audioState: AudioState,
onClick: () -> Unit,
modifier: Modifier,
Expand All @@ -167,7 +178,9 @@ fun RecordAudioButtonSend(
iconResId = R.drawable.ic_send,
contentDescription = R.string.content_description_record_audio_button_send,
buttonColor = colorsScheme().recordAudioStartColor,
bottomText = R.string.record_audio_send_label
bottomText = R.string.record_audio_send_label,
applyAudioFilterState = applyAudioFilterState,
applyAudioFilterClick = { }
)
}

Expand All @@ -180,7 +193,10 @@ private fun RecordAudioButton(
@StringRes contentDescription: Int,
buttonColor: Color,
@StringRes bottomText: Int,
buttonState: WireButtonState = WireButtonState.Default
buttonState: WireButtonState = WireButtonState.Default,
applyAudioFilterState: Boolean,
applyAudioFilterClick: (Boolean) -> Unit,
isAudioFilterEnabled: Boolean = false
) {
Column(
modifier = modifier,
Expand Down Expand Up @@ -213,6 +229,22 @@ private fun RecordAudioButton(
text = stringResource(id = bottomText),
style = MaterialTheme.wireTypography.body02
)

Spacer(modifier = Modifier.height(dimensions().spacing40x))
Row(
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
enabled = isAudioFilterEnabled,
checked = applyAudioFilterState,
onCheckedChange = applyAudioFilterClick
)
Text(
text = stringResource(id = R.string.record_audio_apply_filter_label),
style = MaterialTheme.wireTypography.body01,
color = if (isAudioFilterEnabled) Color.Unspecified else colorsScheme().checkboxTextDisabled
)
}
}
}

Expand All @@ -228,15 +260,24 @@ fun PreviewRecordAudioButtonClose() {
@Composable
fun PreviewRecordAudioButtonEnabled() {
WireTheme {
RecordAudioButtonEnabled(onClick = {}, modifier = Modifier)
RecordAudioButtonEnabled(
onClick = {},
modifier = Modifier,
applyAudioFilterState = false,
applyAudioFilterClick = {}
)
}
}

@PreviewMultipleThemes
@Composable
fun PreviewRecordAudioButtonRecording() {
WireTheme {
RecordAudioButtonRecording(onClick = {}, modifier = Modifier)
RecordAudioButtonRecording(
onClick = {},
modifier = Modifier,
applyAudioFilterState = false
)
}
}

Expand All @@ -254,7 +295,8 @@ fun PreviewRecordAudioButtonSend() {
modifier = Modifier,
outputFile = null,
onPlayAudio = {},
onSliderPositionChange = {}
onSliderPositionChange = {},
applyAudioFilterState = false
)
}
}
Expand All @@ -270,7 +312,9 @@ fun PreviewRecordAudioButton() {
iconResId = R.drawable.ic_microphone_on,
contentDescription = R.string.content_description_record_audio_button_start,
buttonColor = colorsScheme().recordAudioStartColor,
bottomText = R.string.record_audio_start_label
bottomText = R.string.record_audio_start_label,
applyAudioFilterState = false,
applyAudioFilterClick = {}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fun RecordAudioComponent(
// for sending analytics events
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_STOP &&
viewModel.getButtonState() != RecordAudioButtonState.ENABLED
viewModel.state.buttonState != RecordAudioButtonState.ENABLED
) {
viewModel.stopRecording()
}
Expand Down Expand Up @@ -102,52 +102,54 @@ fun RecordAudioComponent(

val buttonModifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = dimensions().spacing80x)
.padding(bottom = dimensions().spacing20x)

when (viewModel.getButtonState()) {
when (viewModel.state.buttonState) {
RecordAudioButtonState.ENABLED -> RecordAudioButtonEnabled(
applyAudioFilterState = viewModel.state.shouldApplyEffects,
applyAudioFilterClick = viewModel::setShouldApplyEffects,
onClick = { recordAudioFlow.launch() },
modifier = buttonModifier
)

RecordAudioButtonState.RECORDING -> RecordAudioButtonRecording(
applyAudioFilterState = viewModel.state.shouldApplyEffects,
onClick = viewModel::stopRecording,
modifier = buttonModifier
)

RecordAudioButtonState.READY_TO_SEND -> RecordAudioButtonSend(
audioState = viewModel.getAudioState(),
applyAudioFilterState = viewModel.state.shouldApplyEffects,
audioState = viewModel.state.audioState,
onClick = {
viewModel.sendRecording(
onAudioRecorded = onAudioRecorded,
) {
viewModel.sendRecording(onAudioRecorded = onAudioRecorded) {
onCloseRecordAudio()
}
},
modifier = buttonModifier,
outputFile = viewModel.getOutputFile(),
outputFile = viewModel.getPlayableAudioFile(),
onPlayAudio = viewModel::onPlayAudio,
onSliderPositionChange = viewModel::onSliderPositionChange
)
}
}

DiscardRecordedAudioDialog(
dialogState = viewModel.getDiscardDialogState(),
dialogState = viewModel.state.discardDialogState,
onDismiss = viewModel::onDismissDiscardDialog,
onDiscard = { viewModel.discardRecording(onCloseRecordAudio) }
)

MicrophonePermissionsDeniedDialog(
dialogState = viewModel.getPermissionsDeniedDialogState(),
dialogState = viewModel.state.permissionsDeniedDialogState,
onDismiss = viewModel::onDismissPermissionsDeniedDialog,
onOpenSettings = {
context.openAppInfoScreen()
}
)

RecordedAudioMaxFileSizeReachedDialog(
dialogState = viewModel.getMaxFileSizeReachedDialogState(),
dialogState = viewModel.state.maxFileSizeReachedDialogState,
onDismiss = viewModel::onDismissMaxFileSizeReachedDialog
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ data class RecordAudioState(
val discardDialogState: RecordAudioDialogState = RecordAudioDialogState.Hidden,
val permissionsDeniedDialogState: RecordAudioDialogState = RecordAudioDialogState.Hidden,
val maxFileSizeReachedDialogState: RecordAudioDialogState = RecordAudioDialogState.Hidden,
val outputFile: File? = null,
val originalOutputFile: File? = null,
val effectsOutputFile: File? = null,
val shouldApplyEffects: Boolean = false,
val audioState: AudioState = AudioState.DEFAULT
)

Expand Down
Loading

0 comments on commit 23177ba

Please sign in to comment.