feat: Implement permanent deletion and restoration of notes with updated UI

This commit is contained in:
2026-05-19 11:40:01 +02:00
parent 2a898111fa
commit f550476177
7 changed files with 236 additions and 132 deletions
+70 -83
View File
@@ -47,6 +47,7 @@ class _HomeScreenState extends State<HomeScreen> {
bool _isLoading = true;
bool _isDragging = false;
bool _isMenuOpen = false;
bool _showDeletedNotes = false;
PointerDeviceKind _lastPointerKind = PointerDeviceKind.mouse;
bool _requiresLongPressToDrag(PointerDeviceKind kind) {
@@ -71,7 +72,9 @@ class _HomeScreenState extends State<HomeScreen> {
Future<void> _loadNotes() async {
try {
final List<Note> storedNotes = await widget.repository.loadNotes();
final List<Note> storedNotes = _showDeletedNotes
? await widget.repository.loadDeletedNotes()
: await widget.repository.loadNotes();
if (!mounted) return;
@@ -95,19 +98,8 @@ class _HomeScreenState extends State<HomeScreen> {
}
if (result is Note) {
final Note createdNote = await widget.repository.createNote(result);
final List<Note> updatedNotes = _normalizeNotes(<Note>[
createdNote,
..._notes,
]);
if (!mounted) {
return;
}
setState(() {
_notes = updatedNotes;
});
await widget.repository.createNote(result);
await _loadNotes();
// Trigger sync after creating a note.
try {
@@ -118,18 +110,7 @@ class _HomeScreenState extends State<HomeScreen> {
Future<void> _deleteNote(Note note) async {
await widget.repository.deleteNote(note);
final List<Note> updatedNotes = _normalizeNotes(
_notes.where((Note item) => item.id != note.id).toList(),
);
if (!mounted) {
return;
}
setState(() {
_notes = updatedNotes;
});
await _loadNotes();
// Trigger sync after deleting a note.
try {
@@ -142,19 +123,10 @@ class _HomeScreenState extends State<HomeScreen> {
return;
}
final List<Note> updatedNotes = [..._notes];
final Note movedNote = updatedNotes.removeAt(oldIndex);
updatedNotes.insert(newIndex, movedNote);
final Note movedNote = _notes[oldIndex];
await widget.repository.moveNote(movedNote, newIndex);
if (!mounted) {
return;
}
setState(() {
_notes = _normalizeNotes(updatedNotes);
});
await _loadNotes();
}
Future<void> _openNoteEditor(Note note) async {
@@ -173,19 +145,9 @@ class _HomeScreenState extends State<HomeScreen> {
}
if (result is Note) {
final int noteIndex = _notes.indexWhere((Note item) => item == note);
if (noteIndex != -1) {
final Note savedNote = await widget.repository.updateNote(result);
final List<Note> updatedNotes = [..._notes];
updatedNotes[noteIndex] = savedNote;
if (!mounted) {
return;
}
setState(() {
_notes = _normalizeNotes(updatedNotes);
});
if (_notes.any((Note item) => item == note)) {
await widget.repository.updateNote(result);
await _loadNotes();
// Trigger sync after editing a note.
try {
await widget.onRequestSync();
@@ -194,12 +156,6 @@ class _HomeScreenState extends State<HomeScreen> {
}
}
List<Note> _normalizeNotes(List<Note> notes) {
return notes.asMap().entries.map((MapEntry<int, Note> entry) {
return entry.value.copyWith(index: entry.key);
}).toList();
}
List<Note> _getFilteredNotes() {
if (_searchQuery.isEmpty) {
return _notes;
@@ -215,6 +171,36 @@ class _HomeScreenState extends State<HomeScreen> {
.toList();
}
Future<void> _handleMenuItemTapped(String item) async {
setState(() {
_isMenuOpen = false;
});
if (item == 'settings') {
widget.onOpenSettings();
return;
}
if (item == 'deleted_notes') {
setState(() {
_showDeletedNotes = true;
_searchQuery = '';
_isLoading = true;
});
await _loadNotes();
return;
}
if (item == 'all_notes') {
setState(() {
_showDeletedNotes = false;
_searchQuery = '';
_isLoading = true;
});
await _loadNotes();
}
}
@override
Widget build(BuildContext context) {
final double width = MediaQuery.of(context).size.width;
@@ -223,8 +209,8 @@ class _HomeScreenState extends State<HomeScreen> {
final Widget body = _isLoading
? const Center(child: CircularProgressIndicator())
: _notes.isEmpty
? const _EmptyState()
: RefreshIndicator(
? _EmptyState(showDeletedNotes: _showDeletedNotes)
: RefreshIndicator(
onRefresh: () async {
await widget.onRequestSync();
},
@@ -599,15 +585,10 @@ class _HomeScreenState extends State<HomeScreen> {
color: const Color.fromRGBO(24, 25, 26, 1),
elevation: 8,
child: MenuDrawer(
onMenuItemTapped: (String item) {
setState(() {
_isMenuOpen = false;
});
if (item == 'settings') {
widget.onOpenSettings();
}
},
onMenuItemTapped: _handleMenuItemTapped,
selectedItem: _showDeletedNotes
? 'deleted_notes'
: 'all_notes',
),
),
),
@@ -618,41 +599,47 @@ class _HomeScreenState extends State<HomeScreen> {
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _openNoteComposer,
child: const MouseRegion(
cursor: SystemMouseCursors.click,
child: Icon(Icons.add),
),
),
floatingActionButton: _showDeletedNotes
? null
: FloatingActionButton(
onPressed: _openNoteComposer,
child: const MouseRegion(
cursor: SystemMouseCursors.click,
child: Icon(Icons.add),
),
),
);
}
}
class _EmptyState extends StatelessWidget {
const _EmptyState();
const _EmptyState({required this.showDeletedNotes});
final bool showDeletedNotes;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: const [
Icon(Icons.note_add_outlined, color: Colors.white54, size: 48),
SizedBox(height: 12),
children: [
const Icon(Icons.note_add_outlined, color: Colors.white54, size: 48),
const SizedBox(height: 12),
Text(
'Aún no hay notas',
style: TextStyle(
showDeletedNotes ? 'No hay notas borradas' : 'Aún no hay notas',
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
SizedBox(height: 8),
const SizedBox(height: 8),
Text(
'Pulsa el botón + para crear la primera.',
showDeletedNotes
? 'Las notas borradas aparecerán aquí para poder restaurarlas.'
: 'Pulsa el botón + para crear la primera.',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white70),
style: const TextStyle(color: Colors.white70),
),
],
),
+12 -9
View File
@@ -93,18 +93,21 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
}
void _deleteNote() {
final bool isDeletedNote = _currentNote.isDeleted;
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
backgroundColor: const Color(0xFF303134),
title: const Text(
'Eliminar nota',
style: TextStyle(color: Colors.white),
title: Text(
isDeletedNote ? 'Eliminar permanentemente' : 'Eliminar nota',
style: const TextStyle(color: Colors.white),
),
content: const Text(
'¿Estás seguro de que deseas eliminar esta nota?',
style: TextStyle(color: Colors.white70),
content: Text(
isDeletedNote
? 'Esta nota ya está borrada. Si la eliminas ahora, se borrará permanentemente.'
: '¿Estás seguro de que deseas eliminar esta nota?',
style: const TextStyle(color: Colors.white70),
),
actions: [
TextButton(
@@ -119,9 +122,9 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
Navigator.of(context).pop();
Navigator.of(context).pop('delete');
},
child: const Text(
'Eliminar',
style: TextStyle(color: Colors.red),
child: Text(
isDeletedNote ? 'Eliminar permanentemente' : 'Eliminar',
style: const TextStyle(color: Colors.red),
),
),
],