feat: Add message deletion functionality with confirmation dialog and options

This commit is contained in:
Janez T
2025-10-15 15:04:09 +02:00
parent 61d0b831ab
commit 52efa03d32
2 changed files with 105 additions and 0 deletions

View File

@@ -284,6 +284,37 @@ class MessagesProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
/// Delete a specific message by ID
void deleteMessage(String messageId) {
final index = _messages.indexWhere((m) => m.id == messageId);
if (index != -1) {
final message = _messages[index];
// If it's a SAR marker message, also remove the marker
if (message.isSarMarker) {
final marker = message.toSarMarker();
if (marker != null) {
_sarMarkers.remove(marker.id);
}
}
// Remove from messages list
_messages.removeAt(index);
// Cancel timeout timer if it exists
if (message.expectedAckTag != null) {
_timeoutTimers[message.expectedAckTag]?.cancel();
_timeoutTimers.remove(message.expectedAckTag);
_pendingSentMessages.remove(message.expectedAckTag);
}
print('🗑️ [MessagesProvider] Message $messageId deleted');
_persistMessages();
notifyListeners();
}
}
/// Clear all messages /// Clear all messages
void clearMessages() { void clearMessages() {
_messages.clear(); _messages.clear();

View File

@@ -498,6 +498,79 @@ class _MessageBubble extends StatelessWidget {
} }
} }
void _showMessageOptions(BuildContext context) {
showModalBottomSheet(
context: context,
backgroundColor: Theme.of(context).colorScheme.surface,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (context) => Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Copy text option
ListTile(
leading: const Icon(Icons.copy),
title: const Text('Copy text'),
onTap: () {
Clipboard.setData(ClipboardData(text: message.text));
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Text copied to clipboard'),
duration: Duration(seconds: 1),
),
);
},
),
// Delete message option
ListTile(
leading: const Icon(Icons.delete, color: Colors.red),
title: const Text('Delete message', style: TextStyle(color: Colors.red)),
onTap: () {
Navigator.pop(context);
_showDeleteConfirmation(context);
},
),
],
),
),
);
}
void _showDeleteConfirmation(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Delete message'),
content: const Text('Are you sure you want to delete this message?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
final messagesProvider = context.read<MessagesProvider>();
messagesProvider.deleteMessage(message.id);
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Message deleted'),
duration: Duration(seconds: 1),
),
);
},
style: TextButton.styleFrom(foregroundColor: Colors.red),
child: const Text('Delete'),
),
],
),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isSarMarker = message.isSarMarker; final isSarMarker = message.isSarMarker;
@@ -518,6 +591,7 @@ class _MessageBubble extends StatelessWidget {
return GestureDetector( return GestureDetector(
onTap: onTap, onTap: onTap,
onLongPress: () => _showMessageOptions(context),
child: Container( child: Container(
margin: const EdgeInsets.only(bottom: 12), margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),