feat: consolidate dialogs (#4506)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
James Rich 2026-02-08 16:45:52 -06:00 committed by GitHub
parent 7bcc51863f
commit ea6d1ffa32
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
59 changed files with 2042 additions and 1659 deletions

View file

@ -19,8 +19,6 @@ package org.meshtastic.feature.messaging
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -36,6 +34,7 @@ import org.meshtastic.core.strings.close
import org.meshtastic.core.strings.message_retry_count
import org.meshtastic.core.strings.relays
import org.meshtastic.core.strings.resend
import org.meshtastic.core.ui.component.MeshtasticDialog
@Suppress("UnusedParameter")
@Composable
@ -49,28 +48,12 @@ fun DeliveryInfo(
maxRetries: Int = 0,
onConfirm: (() -> Unit) = {},
onDismiss: () -> Unit = {},
) = AlertDialog(
onDismissRequest = onDismiss,
dismissButton = {
FilledTonalButton(onClick = onDismiss, modifier = Modifier.padding(horizontal = 16.dp)) {
Text(text = stringResource(Res.string.close))
}
},
confirmButton = {
if (resendOption) {
FilledTonalButton(onClick = onConfirm, modifier = Modifier.padding(horizontal = 16.dp)) {
Text(text = stringResource(Res.string.resend))
}
}
},
title = {
Text(
text = stringResource(title),
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.headlineSmall,
)
},
) = MeshtasticDialog(
title = stringResource(title),
onDismiss = onDismiss,
dismissText = stringResource(Res.string.close),
confirmText = if (resendOption) stringResource(Res.string.resend) else null,
onConfirm = if (resendOption) onConfirm else null,
text = {
Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
text?.let {
@ -98,6 +81,4 @@ fun DeliveryInfo(
}
}
},
shape = androidx.compose.foundation.shape.RoundedCornerShape(16.dp),
containerColor = MaterialTheme.colorScheme.surface,
)

View file

@ -61,7 +61,6 @@ import androidx.compose.material.icons.rounded.SelectAll
import androidx.compose.material.icons.rounded.SpeakerNotesOff
import androidx.compose.material.icons.rounded.Visibility
import androidx.compose.material.icons.rounded.VisibilityOff
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
@ -74,7 +73,6 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -110,7 +108,6 @@ import org.meshtastic.core.model.util.getChannel
import org.meshtastic.core.service.RetryEvent
import org.meshtastic.core.strings.Res
import org.meshtastic.core.strings.alert_bell_text
import org.meshtastic.core.strings.cancel
import org.meshtastic.core.strings.cancel_reply
import org.meshtastic.core.strings.clear_selection
import org.meshtastic.core.strings.copy
@ -135,6 +132,7 @@ import org.meshtastic.core.strings.send
import org.meshtastic.core.strings.type_a_message
import org.meshtastic.core.strings.unknown
import org.meshtastic.core.strings.unknown_channel
import org.meshtastic.core.ui.component.MeshtasticTextDialog
import org.meshtastic.core.ui.component.NodeKeyStatusIcon
import org.meshtastic.core.ui.component.SecurityIcon
import org.meshtastic.core.ui.component.SharedContactDialog
@ -241,11 +239,6 @@ fun MessageScreen(
val listState = rememberLazyListState()
val lastReadMessageTimestamp by
remember(contactKey, contactSettings) {
derivedStateOf { contactSettings[contactKey]?.lastReadMessageTimestamp }
}
// Track unread messages using lightweight metadata queries
val hasUnreadMessages by viewModel.hasUnreadMessages(contactKey).collectAsStateWithLifecycle(initialValue = false)
val firstUnreadMessageUuid by
@ -307,7 +300,11 @@ fun MessageScreen(
is MessageScreenEvent.NavigateToNodeDetails -> navigateToNodeDetails(event.nodeNum)
MessageScreenEvent.NavigateBack -> onNavigateBack()
is MessageScreenEvent.CopyToClipboard -> {
clipboardManager.nativeClipboard.setPrimaryClip(ClipData.newPlainText(event.text, event.text))
coroutineScope.launch {
clipboardManager.setClipEntry(
androidx.compose.ui.platform.ClipEntry(ClipData.newPlainText(event.text, event.text)),
)
}
selectedMessageIds.value = emptySet()
}
}
@ -644,13 +641,12 @@ private fun String.limitBytes(maxBytes: Int): String {
private fun DeleteMessageDialog(count: Int, onConfirm: () -> Unit, onDismiss: () -> Unit) {
val deleteMessagesString = pluralStringResource(Res.plurals.delete_messages, count, count)
AlertDialog(
onDismissRequest = onDismiss,
shape = RoundedCornerShape(16.dp),
title = { Text(stringResource(Res.string.delete_messages_title)) },
text = { Text(text = deleteMessagesString) },
confirmButton = { TextButton(onClick = onConfirm) { Text(stringResource(Res.string.delete)) } },
dismissButton = { TextButton(onClick = onDismiss) { Text(stringResource(Res.string.cancel)) } },
MeshtasticTextDialog(
titleRes = Res.string.delete_messages_title,
message = deleteMessagesString,
confirmTextRes = Res.string.delete,
onConfirm = onConfirm,
onDismiss = onDismiss,
)
}

View file

@ -16,11 +16,9 @@
*/
package org.meshtastic.feature.messaging
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@ -38,8 +36,6 @@ import androidx.compose.material.icons.rounded.Add
import androidx.compose.material.icons.rounded.DragHandle
import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.FastForward
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
@ -63,8 +59,6 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusEvent
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
@ -84,6 +78,7 @@ import org.meshtastic.core.strings.quick_chat_instant
import org.meshtastic.core.strings.quick_chat_new
import org.meshtastic.core.strings.save
import org.meshtastic.core.ui.component.MainAppBar
import org.meshtastic.core.ui.component.MeshtasticDialog
import org.meshtastic.core.ui.component.dragContainer
import org.meshtastic.core.ui.component.dragDropItemsIndexed
import org.meshtastic.core.ui.component.rememberDragDropState
@ -185,20 +180,17 @@ private fun EditQuickChatDialog(
}
}
AlertDialog(
onDismissRequest = onDismiss,
MeshtasticDialog(
onDismiss = onDismiss,
title = stringResource(title),
confirmText = stringResource(Res.string.save),
onConfirm = {
onSave(actionInput)
onDismiss()
},
dismissText = stringResource(Res.string.cancel),
text = {
Column(modifier = Modifier.fillMaxWidth()) {
Text(
text = stringResource(title),
modifier = Modifier.fillMaxWidth(),
style =
MaterialTheme.typography.titleLarge.copy(
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
),
)
Spacer(modifier = Modifier.height(8.dp))
OutlinedTextFieldWithCounter(
@ -257,39 +249,19 @@ private fun EditQuickChatDialog(
},
)
}
}
},
confirmButton = {
FlowRow(
modifier = Modifier.fillMaxWidth().padding(start = 24.dp, end = 24.dp, bottom = 16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
TextButton(modifier = Modifier.weight(1f), onClick = onDismiss) {
Text(stringResource(Res.string.cancel))
}
if (!newQuickChat) {
Button(
modifier = Modifier.weight(1f),
Spacer(modifier = Modifier.height(16.dp))
TextButton(
modifier = Modifier.fillMaxWidth(),
onClick = {
onDelete(actionInput)
onDismiss()
},
) {
Text(text = stringResource(Res.string.delete))
Text(text = stringResource(Res.string.delete), color = MaterialTheme.colorScheme.error)
}
}
Button(
modifier = Modifier.weight(1f),
onClick = {
onSave(actionInput)
onDismiss()
},
enabled = actionInput.name.isNotEmpty() && actionInput.message.isNotEmpty(),
) {
Text(text = stringResource(Res.string.save))
}
}
},
)

View file

@ -19,8 +19,6 @@ package org.meshtastic.feature.messaging.component
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -42,6 +40,7 @@ import org.meshtastic.core.strings.retry_dialog_confirm
import org.meshtastic.core.strings.retry_dialog_message
import org.meshtastic.core.strings.retry_dialog_reaction_message
import org.meshtastic.core.strings.retry_dialog_title
import org.meshtastic.core.ui.component.MeshtasticDialog
private const val COUNTDOWN_DELAY_MS = 1000L
private const val MESSAGE_PREVIEW_LENGTH = 50
@ -120,22 +119,13 @@ fun RetryConfirmationDialog(
onTimeout()
}
AlertDialog(
onDismissRequest = { /* Prevent dismissal by clicking outside */ },
dismissButton = {
FilledTonalButton(onClick = onCancel) { Text(text = stringResource(Res.string.retry_dialog_cancel)) }
},
confirmButton = {
FilledTonalButton(onClick = onConfirm) { Text(text = stringResource(Res.string.retry_dialog_confirm)) }
},
title = {
Text(
text = stringResource(Res.string.retry_dialog_title),
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.headlineSmall,
)
},
MeshtasticDialog(
onDismiss = onCancel,
dismissText = stringResource(Res.string.retry_dialog_cancel),
confirmText = stringResource(Res.string.retry_dialog_confirm),
onConfirm = onConfirm,
title = stringResource(Res.string.retry_dialog_title),
text = { RetryDialogContent(retryEvent, timeRemaining) },
dismissable = false,
)
}