Enhance cleanup dialog with sensitivity slider for problematic entries

This commit is contained in:
2025-05-20 12:44:53 +02:00
parent 621e85c747
commit 4339763261
2 changed files with 178 additions and 108 deletions

View File

@@ -953,7 +953,10 @@ class MainPageState extends State<MainPage> with WindowListener {
// Show cleanup dialog // Show cleanup dialog
void _showCleanupDialog() async { void _showCleanupDialog() async {
final problematicEntries = await findProblematicEntries(); double sensitivity = 0.7; // Default 70%
final problematicEntries = await findProblematicEntries(
maxCharPercentage: sensitivity,
);
if (!mounted) return; if (!mounted) return;
@@ -969,13 +972,44 @@ class MainPageState extends State<MainPage> with WindowListener {
height: MediaQuery.of(context).size.height * 0.7, height: MediaQuery.of(context).size.height * 0.7,
child: Column( child: Column(
children: [ children: [
Row(
children: [
const Text('Sensitivity: '),
Expanded(
child: Slider(
value: sensitivity,
min: 0.3,
max: 0.9,
divisions: 12,
label: '${(sensitivity * 100).toInt()}%',
onChanged: (value) async {
dialogSetState(() {
sensitivity =
(value * 100).round() /
100; // Round to 2 decimal places
});
// Refresh results with new sensitivity
final newResults = await findProblematicEntries(
maxCharPercentage: sensitivity,
);
dialogSetState(() {
problematicEntries.clear();
problematicEntries.addAll(newResults);
});
},
),
),
Text('${(sensitivity * 100).toInt()}%'),
],
),
Text( Text(
'Found ${problematicEntries.length} potentially problematic entries', 'Found ${problematicEntries.length} potentially problematic entries',
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
Expanded( Expanded(
child: problematicEntries.isEmpty child:
problematicEntries.isEmpty
? const Center( ? const Center(
child: Text('No problematic entries found!'), child: Text('No problematic entries found!'),
) )
@@ -993,7 +1027,8 @@ class MainPageState extends State<MainPage> with WindowListener {
), ),
), ),
subtitle: Column( subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'Reason: ${note.problemReason}', 'Reason: ${note.problemReason}',
@@ -1018,7 +1053,8 @@ class MainPageState extends State<MainPage> with WindowListener {
// Navigate to the note in main window // Navigate to the note in main window
setState(() { setState(() {
_currentlyDisplayedNote = note; _currentlyDisplayedNote = note;
_previousEntryController.text = note.content; _previousEntryController.text =
note.content;
}); });
_checkNavigation(); _checkNavigation();
}, },
@@ -1026,39 +1062,67 @@ class MainPageState extends State<MainPage> with WindowListener {
IconButton( IconButton(
icon: const Icon(Icons.delete), icon: const Icon(Icons.delete),
color: Colors.red, color: Colors.red,
tooltip: 'Delete (hold Shift to skip confirmation)', tooltip:
'Delete (hold Shift to skip confirmation)',
onPressed: () async { onPressed: () async {
// Check if shift is pressed // Check if shift is pressed
final isShiftPressed = HardwareKeyboard.instance.isShiftPressed; final isShiftPressed =
HardwareKeyboard
.instance
.isShiftPressed;
bool shouldDelete = isShiftPressed; bool shouldDelete =
isShiftPressed;
if (!isShiftPressed) { if (!isShiftPressed) {
// Show confirmation dialog // Show confirmation dialog
shouldDelete = await showDialog<bool>( shouldDelete =
await showDialog<bool>(
context: context, context: context,
builder: (context) => AlertDialog( builder:
title: const Text('Delete Entry?'), (
context,
) => AlertDialog(
title: const Text(
'Delete Entry?',
),
content: const Text( content: const Text(
'Are you sure you want to delete this entry? This action cannot be undone.', 'Are you sure you want to delete this entry? This action cannot be undone.',
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(false), onPressed:
child: const Text('Cancel'), () => Navigator.of(
context,
).pop(
false,
),
child:
const Text(
'Cancel',
),
), ),
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(true), onPressed:
child: const Text('Delete'), () => Navigator.of(
context,
).pop(true),
child:
const Text(
'Delete',
),
), ),
], ],
), ),
) ?? false; ) ??
false;
} }
if (shouldDelete) { if (shouldDelete) {
await deleteNote(note.date); await deleteNote(note.date);
dialogSetState(() { dialogSetState(() {
problematicEntries.removeAt(index); problematicEntries.removeAt(
index,
);
}); });
} }
}, },

View File

@@ -162,12 +162,12 @@ Future<List<Note>> searchNotes(String query) async {
} }
// Find potentially problematic entries based on character distribution // Find potentially problematic entries based on character distribution
Future<List<Note>> findProblematicEntries() async { Future<List<Note>> findProblematicEntries({
const double maxCharPercentage = 0.7; // If a single char makes up more than 70%, it's suspicious double maxCharPercentage = 0.7,
const int minLength = 10; // Only check notes longer than this }) async {
// Simple SQLite query that counts character occurrences using replace // Simple SQLite query that counts character occurrences using replace
final List<Map<String, dynamic>> results = await DB.db.rawQuery(''' final List<Map<String, dynamic>> results = await DB.db.rawQuery(
'''
WITH char_counts AS ( WITH char_counts AS (
SELECT SELECT
id, id,
@@ -178,18 +178,24 @@ Future<List<Note>> findProblematicEntries() async {
length(content) as total_length, length(content) as total_length,
cast(length(content) - length(replace(content, substr(content, 1, 1), '')) as float) / length(content) as percentage cast(length(content) - length(replace(content, substr(content, 1, 1), '')) as float) / length(content) as percentage
FROM notes FROM notes
WHERE length(content) >= ?
) )
SELECT * SELECT *
FROM char_counts FROM char_counts
WHERE percentage > ? WHERE percentage > ?
ORDER BY date DESC ORDER BY date DESC
''', [minLength, maxCharPercentage]); ''',
[maxCharPercentage],
);
return results.map((row) => Note( return results
.map(
(row) => Note(
date: row['date'] as String, date: row['date'] as String,
content: row['content'] as String, content: row['content'] as String,
isProblematic: true, isProblematic: true,
problemReason: 'Character "${row['char']}" makes up ${(row['percentage'] * 100).toStringAsFixed(1)}% of the content', problemReason:
)).toList(); 'Character "${row['char']}" makes up ${(row['percentage'] * 100).toStringAsFixed(1)}% of the content',
),
)
.toList();
} }