refactor: Replace MaterialAlertDialogBuilder with Compose AlertDialog

Replace all 11 instances of MaterialAlertDialogBuilder across 5 files with Compose AlertDialog. Use sealed dialog state per screen to prevent dialog stacking. Add shared ConfirmationDialog composable. Delete dead ErrorDialog.kt.
This commit is contained in:
darken
2026-03-09 12:46:23 +00:00
committed by Matthias Urhahn
parent cba239f411
commit d7d9d53ff3
6 changed files with 272 additions and 176 deletions
@@ -0,0 +1,32 @@
package eu.darken.capod.common.compose
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
@Composable
fun ConfirmationDialog(
title: String,
message: String,
confirmLabel: String,
dismissLabel: String,
onConfirm: () -> Unit,
onDismiss: () -> Unit,
) {
AlertDialog(
onDismissRequest = onDismiss,
title = { Text(text = title) },
text = { Text(text = message) },
confirmButton = {
TextButton(onClick = onConfirm) {
Text(text = confirmLabel)
}
},
dismissButton = {
TextButton(onClick = onDismiss) {
Text(text = dismissLabel)
}
},
)
}
@@ -17,10 +17,11 @@ import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.compose.ui.graphics.luminance import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.res.stringResource
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import eu.darken.capod.R import eu.darken.capod.R
import eu.darken.capod.common.compose.ConfirmationDialog
import eu.darken.capod.common.debug.logging.logTag import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.theming.CapodTheme import eu.darken.capod.common.theming.CapodTheme
import eu.darken.capod.common.uix.Activity2 import eu.darken.capod.common.uix.Activity2
@@ -29,6 +30,11 @@ import eu.darken.capod.main.core.currentThemeState
import eu.darken.capod.main.core.themeState import eu.darken.capod.main.core.themeState
import javax.inject.Inject import javax.inject.Inject
private sealed interface RecorderDialog {
data object SentConfirm : RecorderDialog
data object DeleteConfirm : RecorderDialog
}
@AndroidEntryPoint @AndroidEntryPoint
class RecorderActivity : Activity2() { class RecorderActivity : Activity2() {
@@ -58,6 +64,7 @@ class RecorderActivity : Activity2() {
} }
var hasShared by remember { mutableStateOf(false) } var hasShared by remember { mutableStateOf(false) }
var dialog by remember { mutableStateOf<RecorderDialog?>(null) }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
vm.events.collect { event -> vm.events.collect { event ->
@@ -71,50 +78,44 @@ class RecorderActivity : Activity2() {
} }
} }
var showSentConfirm by remember { mutableStateOf(false) }
LifecycleResumeEffect(hasShared) { LifecycleResumeEffect(hasShared) {
if (hasShared) { if (hasShared) {
showSentConfirm = true dialog = RecorderDialog.SentConfirm
hasShared = false hasShared = false
} }
onPauseOrDispose {} onPauseOrDispose {}
} }
if (showSentConfirm) { when (dialog) {
LaunchedEffect(Unit) { is RecorderDialog.SentConfirm -> {
MaterialAlertDialogBuilder(this@RecorderActivity).apply { ConfirmationDialog(
setTitle(R.string.support_debuglog_sent_title) title = stringResource(R.string.support_debuglog_sent_title),
setMessage(R.string.support_debuglog_sent_message) message = stringResource(R.string.support_debuglog_sent_message),
setPositiveButton(R.string.general_done_action) { _, _ -> confirmLabel = stringResource(R.string.general_done_action),
showSentConfirm = false dismissLabel = stringResource(R.string.general_cancel_action),
onConfirm = {
dialog = null
vm.discard() vm.discard()
} },
setNegativeButton(R.string.general_cancel_action) { _, _ -> onDismiss = { dialog = null },
showSentConfirm = false )
}
setOnCancelListener { showSentConfirm = false }
}.show()
} }
}
var showDeleteConfirm by remember { mutableStateOf(false) } is RecorderDialog.DeleteConfirm -> {
ConfirmationDialog(
if (showDeleteConfirm) { title = stringResource(R.string.support_debuglog_session_delete_title),
LaunchedEffect(Unit) { message = stringResource(R.string.support_debuglog_session_delete_message),
MaterialAlertDialogBuilder(this@RecorderActivity).apply { confirmLabel = stringResource(R.string.profiles_delete_action),
setTitle(R.string.support_debuglog_session_delete_title) dismissLabel = stringResource(R.string.general_cancel_action),
setMessage(R.string.support_debuglog_session_delete_message) onConfirm = {
setPositiveButton(R.string.profiles_delete_action) { _, _ -> dialog = null
showDeleteConfirm = false
vm.discard() vm.discard()
} },
setNegativeButton(R.string.general_cancel_action) { _, _ -> onDismiss = { dialog = null },
showDeleteConfirm = false )
}
setOnCancelListener { showDeleteConfirm = false }
}.show()
} }
null -> {}
} }
val state by vm.state.collectAsStateWithLifecycle(initialValue = null) val state by vm.state.collectAsStateWithLifecycle(initialValue = null)
@@ -123,7 +124,7 @@ class RecorderActivity : Activity2() {
state = it, state = it,
onShare = { vm.share() }, onShare = { vm.share() },
onKeep = { vm.keep() }, onKeep = { vm.keep() },
onDiscard = { showDeleteConfirm = true }, onDiscard = { dialog = RecorderDialog.DeleteConfirm },
onPrivacyPolicy = { vm.goPrivacyPolicy() }, onPrivacyPolicy = { vm.goPrivacyPolicy() },
) )
} }
@@ -1,24 +1,55 @@
package eu.darken.capod.common.debug.recording.ui package eu.darken.capod.common.debug.recording.ui
import android.content.Context import androidx.compose.foundation.layout.Column
import com.google.android.material.dialog.MaterialAlertDialogBuilder import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.darken.capod.R import eu.darken.capod.R
import eu.darken.capod.common.PrivacyPolicy
import eu.darken.capod.common.WebpageTool
class RecorderConsentDialog( @Composable
private val context: Context, fun RecorderConsentDialog(
private val webpageTool: WebpageTool onStartRecord: () -> Unit,
onOpenPrivacyPolicy: () -> Unit,
onDismiss: () -> Unit,
) { ) {
fun showDialog(onStartRecord: () -> Unit) { AlertDialog(
MaterialAlertDialogBuilder(context).apply { onDismissRequest = onDismiss,
setTitle(R.string.support_debuglog_label) title = { Text(text = stringResource(R.string.support_debuglog_label)) },
setMessage(R.string.settings_debuglog_explanation) text = {
setPositiveButton(R.string.debug_debuglog_record_action) { _, _ -> onStartRecord() } Column(modifier = Modifier.fillMaxWidth()) {
setNegativeButton(R.string.general_cancel_action) { _, _ -> } Text(text = stringResource(R.string.settings_debuglog_explanation))
setNeutralButton(R.string.settings_privacy_policy_label) { _, _ -> Spacer(modifier = Modifier.height(8.dp))
webpageTool.open(PrivacyPolicy.URL) TextButton(
onClick = {
onOpenPrivacyPolicy()
onDismiss()
},
modifier = Modifier.align(Alignment.End),
) {
Text(text = stringResource(R.string.settings_privacy_policy_label))
}
} }
}.show() },
} confirmButton = {
} TextButton(onClick = {
onDismiss()
onStartRecord()
}) {
Text(text = stringResource(R.string.debug_debuglog_record_action))
}
},
dismissButton = {
TextButton(onClick = onDismiss) {
Text(text = stringResource(R.string.general_cancel_action))
}
},
)
}
@@ -1,19 +0,0 @@
package eu.darken.capod.common.error
import android.content.Context
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.darken.capod.R
fun Throwable.asErrorDialogBuilder(
context: Context
) = MaterialAlertDialogBuilder(context).apply {
val error = this@asErrorDialogBuilder
val localizedError = error.localized(context)
setTitle(localizedError.label)
setMessage(localizedError.description)
setPositiveButton(android.R.string.ok) { _, _ ->
}
}
@@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.twotone.ArrowBack import androidx.compose.material.icons.automirrored.twotone.ArrowBack
import androidx.compose.material.icons.automirrored.twotone.MenuBook import androidx.compose.material.icons.automirrored.twotone.MenuBook
@@ -25,6 +24,7 @@ import androidx.compose.material.icons.twotone.Delete
import androidx.compose.material.icons.twotone.FiberManualRecord import androidx.compose.material.icons.twotone.FiberManualRecord
import androidx.compose.material.icons.twotone.Settings import androidx.compose.material.icons.twotone.Settings
import androidx.compose.material.icons.twotone.Warning import androidx.compose.material.icons.twotone.Warning
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
@@ -32,6 +32,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -50,10 +51,10 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.darken.capod.R import eu.darken.capod.R
import eu.darken.capod.common.PrivacyPolicy import eu.darken.capod.common.PrivacyPolicy
import eu.darken.capod.common.WebpageTool import eu.darken.capod.common.WebpageTool
import eu.darken.capod.common.compose.ConfirmationDialog
import eu.darken.capod.common.compose.Preview2 import eu.darken.capod.common.compose.Preview2
import eu.darken.capod.common.compose.PreviewWrapper import eu.darken.capod.common.compose.PreviewWrapper
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -65,6 +66,13 @@ import eu.darken.capod.common.navigation.NavigationEventHandler
import eu.darken.capod.common.settings.SettingsBaseItem import eu.darken.capod.common.settings.SettingsBaseItem
import eu.darken.capod.common.settings.SettingsCategoryHeader import eu.darken.capod.common.settings.SettingsCategoryHeader
private sealed interface SupportDialog {
data object Consent : SupportDialog
data object ShortRecordingWarning : SupportDialog
data class DeleteSession(val sessionId: String) : SupportDialog
data object ClearLogs : SupportDialog
}
@Composable @Composable
fun SupportScreenHost(vm: SupportViewModel = hiltViewModel()) { fun SupportScreenHost(vm: SupportViewModel = hiltViewModel()) {
ErrorEventHandler(vm) ErrorEventHandler(vm)
@@ -78,19 +86,17 @@ fun SupportScreenHost(vm: SupportViewModel = hiltViewModel()) {
val state by vm.state.collectAsStateWithLifecycle(initialValue = null) val state by vm.state.collectAsStateWithLifecycle(initialValue = null)
var showShortRecordingWarning by remember { mutableStateOf(false) } var dialog by remember { mutableStateOf<SupportDialog?>(null) }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
vm.events.collect { event -> vm.events.collect { event ->
when (event) { when (event) {
SupportViewModel.Event.ShowConsentDialog -> { SupportViewModel.Event.ShowConsentDialog -> {
RecorderConsentDialog(context, WebpageTool(context)).showDialog { dialog = SupportDialog.Consent
vm.startDebugLog()
}
} }
SupportViewModel.Event.ShowShortRecordingWarning -> { SupportViewModel.Event.ShowShortRecordingWarning -> {
showShortRecordingWarning = true dialog = SupportDialog.ShortRecordingWarning
} }
is SupportViewModel.Event.OpenRecorderActivity -> { is SupportViewModel.Event.OpenRecorderActivity -> {
@@ -103,12 +109,69 @@ fun SupportScreenHost(vm: SupportViewModel = hiltViewModel()) {
} }
} }
if (showShortRecordingWarning) { when (val d = dialog) {
ShortRecordingWarningDialog( is SupportDialog.Consent -> {
context = context, RecorderConsentDialog(
onDismiss = { showShortRecordingWarning = false }, onStartRecord = {
onStopAnyway = { vm.forceStopDebugLog() }, vm.startDebugLog()
) },
onOpenPrivacyPolicy = {
WebpageTool(context).open(PrivacyPolicy.URL)
},
onDismiss = { dialog = null },
)
}
is SupportDialog.ShortRecordingWarning -> {
AlertDialog(
onDismissRequest = { dialog = null },
title = { Text(text = stringResource(R.string.debug_debuglog_short_recording_title)) },
text = { Text(text = stringResource(R.string.debug_debuglog_short_recording_message)) },
confirmButton = {
TextButton(onClick = { dialog = null }) {
Text(text = stringResource(R.string.debug_debuglog_short_recording_continue))
}
},
dismissButton = {
TextButton(onClick = {
dialog = null
vm.forceStopDebugLog()
}) {
Text(text = stringResource(R.string.debug_debuglog_short_recording_stop))
}
},
)
}
is SupportDialog.DeleteSession -> {
ConfirmationDialog(
title = stringResource(R.string.support_debuglog_session_delete_title),
message = stringResource(R.string.support_debuglog_session_delete_message),
confirmLabel = stringResource(R.string.profiles_delete_action),
dismissLabel = stringResource(R.string.general_cancel_action),
onConfirm = {
dialog = null
vm.deleteSession(d.sessionId)
},
onDismiss = { dialog = null },
)
}
is SupportDialog.ClearLogs -> {
ConfirmationDialog(
title = stringResource(R.string.support_debuglog_session_delete_title),
message = stringResource(R.string.support_debuglog_clear_all_message),
confirmLabel = stringResource(R.string.profiles_delete_action),
dismissLabel = stringResource(R.string.general_cancel_action),
onConfirm = {
dialog = null
vm.clearDebugLogs()
},
onDismiss = { dialog = null },
)
}
null -> {}
} }
state?.let { state?.let {
@@ -122,53 +185,13 @@ fun SupportScreenHost(vm: SupportViewModel = hiltViewModel()) {
onTroubleShooter = { vm.goToTroubleShooter() }, onTroubleShooter = { vm.goToTroubleShooter() },
onDebugLogToggle = { vm.onDebugLogToggle() }, onDebugLogToggle = { vm.onDebugLogToggle() },
onOpenSession = { vm.openSession(it) }, onOpenSession = { vm.openSession(it) },
onDeleteSession = { id -> onDeleteSession = { id -> dialog = SupportDialog.DeleteSession(id) },
MaterialAlertDialogBuilder(context).apply {
setTitle(R.string.support_debuglog_session_delete_title)
setMessage(R.string.support_debuglog_session_delete_message)
setPositiveButton(R.string.profiles_delete_action) { _, _ ->
vm.deleteSession(id)
}
setNegativeButton(R.string.general_cancel_action) { _, _ -> }
}.show()
},
onStopRecording = { vm.onDebugLogToggle() }, onStopRecording = { vm.onDebugLogToggle() },
onClearLogs = { onClearLogs = { dialog = SupportDialog.ClearLogs },
MaterialAlertDialogBuilder(context).apply {
setTitle(R.string.support_debuglog_session_delete_title)
setMessage(R.string.support_debuglog_clear_all_message)
setPositiveButton(R.string.profiles_delete_action) { _, _ ->
vm.clearDebugLogs()
}
setNegativeButton(R.string.general_cancel_action) { _, _ -> }
}.show()
},
) )
} }
} }
@Composable
private fun ShortRecordingWarningDialog(
context: android.content.Context,
onDismiss: () -> Unit,
onStopAnyway: () -> Unit,
) {
LaunchedEffect(Unit) {
MaterialAlertDialogBuilder(context).apply {
setTitle(R.string.debug_debuglog_short_recording_title)
setMessage(R.string.debug_debuglog_short_recording_message)
setPositiveButton(R.string.debug_debuglog_short_recording_continue) { _, _ ->
onDismiss()
}
setNegativeButton(R.string.debug_debuglog_short_recording_stop) { _, _ ->
onDismiss()
onStopAnyway()
}
setOnCancelListener { onDismiss() }
}.show()
}
}
@Composable @Composable
fun SupportScreen( fun SupportScreen(
state: SupportViewModel.State, state: SupportViewModel.State,
@@ -23,6 +23,7 @@ import androidx.compose.material.icons.twotone.BugReport
import androidx.compose.material.icons.twotone.Cancel import androidx.compose.material.icons.twotone.Cancel
import androidx.compose.material.icons.twotone.Delete import androidx.compose.material.icons.twotone.Delete
import androidx.compose.material.icons.twotone.Email import androidx.compose.material.icons.twotone.Email
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
@@ -37,6 +38,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -55,15 +57,23 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect import androidx.lifecycle.compose.LifecycleResumeEffect
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.darken.capod.R import eu.darken.capod.R
import eu.darken.capod.common.PrivacyPolicy
import eu.darken.capod.common.WebpageTool import eu.darken.capod.common.WebpageTool
import eu.darken.capod.common.compose.ConfirmationDialog
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import eu.darken.capod.common.debug.recording.ui.RecorderConsentDialog import eu.darken.capod.common.debug.recording.ui.RecorderConsentDialog
import eu.darken.capod.common.error.ErrorEventHandler import eu.darken.capod.common.error.ErrorEventHandler
import eu.darken.capod.common.navigation.NavigationEventHandler import eu.darken.capod.common.navigation.NavigationEventHandler
import eu.darken.capod.main.ui.settings.support.contactform.ContactFormViewModel.Category import eu.darken.capod.main.ui.settings.support.contactform.ContactFormViewModel.Category
private sealed interface ContactFormDialog {
data object SentConfirm : ContactFormDialog
data object Consent : ContactFormDialog
data object ShortRecordingWarning : ContactFormDialog
data class DeleteSession(val sessionId: String) : ContactFormDialog
}
@Composable @Composable
fun ContactFormScreenHost(vm: ContactFormViewModel = hiltViewModel()) { fun ContactFormScreenHost(vm: ContactFormViewModel = hiltViewModel()) {
ErrorEventHandler(vm) ErrorEventHandler(vm)
@@ -73,36 +83,17 @@ fun ContactFormScreenHost(vm: ContactFormViewModel = hiltViewModel()) {
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
var hasSentEmail by remember { mutableStateOf(false) } var hasSentEmail by remember { mutableStateOf(false) }
var showSentConfirm by remember { mutableStateOf(false) } var dialog by remember { mutableStateOf<ContactFormDialog?>(null) }
LifecycleResumeEffect(hasSentEmail) { LifecycleResumeEffect(hasSentEmail) {
vm.refreshLogSessions() vm.refreshLogSessions()
if (hasSentEmail) { if (hasSentEmail) {
showSentConfirm = true dialog = ContactFormDialog.SentConfirm
hasSentEmail = false hasSentEmail = false
} }
onPauseOrDispose {} onPauseOrDispose {}
} }
if (showSentConfirm) {
LaunchedEffect(Unit) {
MaterialAlertDialogBuilder(context).apply {
setTitle(R.string.support_contact_sent_title)
setMessage(R.string.support_contact_sent_message)
setPositiveButton(R.string.general_done_action) { _, _ ->
showSentConfirm = false
vm.confirmSent()
}
setNegativeButton(R.string.general_cancel_action) { _, _ ->
showSentConfirm = false
}
setOnCancelListener { showSentConfirm = false }
}.show()
}
}
var showShortRecordingWarning by remember { mutableStateOf(false) }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
vm.events.collect { event -> vm.events.collect { event ->
when (event) { when (event) {
@@ -123,33 +114,79 @@ fun ContactFormScreenHost(vm: ContactFormViewModel = hiltViewModel()) {
} }
ContactFormViewModel.Event.ShowConsentDialog -> { ContactFormViewModel.Event.ShowConsentDialog -> {
RecorderConsentDialog(context, WebpageTool(context)).showDialog { dialog = ContactFormDialog.Consent
vm.doStartRecording()
}
} }
ContactFormViewModel.Event.ShowShortRecordingWarning -> { ContactFormViewModel.Event.ShowShortRecordingWarning -> {
showShortRecordingWarning = true dialog = ContactFormDialog.ShortRecordingWarning
} }
} }
} }
} }
if (showShortRecordingWarning) { when (val d = dialog) {
LaunchedEffect(Unit) { is ContactFormDialog.SentConfirm -> {
MaterialAlertDialogBuilder(context).apply { ConfirmationDialog(
setTitle(R.string.debug_debuglog_short_recording_title) title = stringResource(R.string.support_contact_sent_title),
setMessage(R.string.debug_debuglog_short_recording_message) message = stringResource(R.string.support_contact_sent_message),
setPositiveButton(R.string.debug_debuglog_short_recording_continue) { _, _ -> confirmLabel = stringResource(R.string.general_done_action),
showShortRecordingWarning = false dismissLabel = stringResource(R.string.general_cancel_action),
} onConfirm = {
setNegativeButton(R.string.debug_debuglog_short_recording_stop) { _, _ -> dialog = null
showShortRecordingWarning = false vm.confirmSent()
vm.forceStopRecording() },
} onDismiss = { dialog = null },
setOnCancelListener { showShortRecordingWarning = false } )
}.show()
} }
is ContactFormDialog.Consent -> {
RecorderConsentDialog(
onStartRecord = {
vm.doStartRecording()
},
onOpenPrivacyPolicy = {
WebpageTool(context).open(PrivacyPolicy.URL)
},
onDismiss = { dialog = null },
)
}
is ContactFormDialog.ShortRecordingWarning -> {
AlertDialog(
onDismissRequest = { dialog = null },
title = { Text(text = stringResource(R.string.debug_debuglog_short_recording_title)) },
text = { Text(text = stringResource(R.string.debug_debuglog_short_recording_message)) },
confirmButton = {
TextButton(onClick = { dialog = null }) {
Text(text = stringResource(R.string.debug_debuglog_short_recording_continue))
}
},
dismissButton = {
TextButton(onClick = {
dialog = null
vm.forceStopRecording()
}) {
Text(text = stringResource(R.string.debug_debuglog_short_recording_stop))
}
},
)
}
is ContactFormDialog.DeleteSession -> {
ConfirmationDialog(
title = stringResource(R.string.support_contact_debuglog_delete_title),
message = stringResource(R.string.support_contact_debuglog_delete_message),
confirmLabel = stringResource(R.string.profiles_delete_action),
dismissLabel = stringResource(R.string.general_cancel_action),
onConfirm = {
dialog = null
vm.deleteLogSession(d.sessionId)
},
onDismiss = { dialog = null },
)
}
null -> {}
} }
val state by vm.state.collectAsStateWithLifecycle(initialValue = null) val state by vm.state.collectAsStateWithLifecycle(initialValue = null)
@@ -162,16 +199,7 @@ fun ContactFormScreenHost(vm: ContactFormViewModel = hiltViewModel()) {
onDescriptionChange = { vm.updateDescription(it) }, onDescriptionChange = { vm.updateDescription(it) },
onExpectedChange = { vm.updateExpectedBehavior(it) }, onExpectedChange = { vm.updateExpectedBehavior(it) },
onSelectSession = { vm.selectLogSession(it) }, onSelectSession = { vm.selectLogSession(it) },
onDeleteSession = { id -> onDeleteSession = { id -> dialog = ContactFormDialog.DeleteSession(id) },
MaterialAlertDialogBuilder(context).apply {
setTitle(R.string.support_contact_debuglog_delete_title)
setMessage(R.string.support_contact_debuglog_delete_message)
setPositiveButton(R.string.profiles_delete_action) { _, _ ->
vm.deleteLogSession(id)
}
setNegativeButton(R.string.general_cancel_action) { _, _ -> }
}.show()
},
onStartRecording = { vm.startRecording() }, onStartRecording = { vm.startRecording() },
onStopRecording = { vm.stopRecording() }, onStopRecording = { vm.stopRecording() },
onSend = { vm.send() }, onSend = { vm.send() },