cache note metadata at load time to eliminate per-search file I/O
_filterNotes was calling note.readAsStringSync() and _extractTags() for every note on every keystroke, plus recomputing path.relative() each time. For large collections with many subdirectories this is O(n * disk). Fix: build three maps during _loadNotes (which already reads every file once) and use them in _filterNotes instead of touching the filesystem: - _noteRelativePaths: pre-lowercased relative path per note - _noteContentLower: pre-lowercased content for full-text search - noteTags: already existed, now actually used in filter _filterNotes now does only in-memory map lookups and string.contains checks — no file reads, no regex, no path computation per keystroke. Also fix _createNewNote: the Navigator.push was not awaited so _loadNotes() was never called on return, leaving stale caches after editing a freshly created note. Now awaits the push and reloads on return, mirroring the existing-note tap behaviour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6470a878fd
commit
f91484d6d4
1 changed files with 21 additions and 11 deletions
|
|
@ -40,6 +40,8 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
||||||
int _visibleLimit = 30;
|
int _visibleLimit = 30;
|
||||||
bool _isLoadingMore = false;
|
bool _isLoadingMore = false;
|
||||||
Map<File, Set<String>> noteTags = {};
|
Map<File, Set<String>> noteTags = {};
|
||||||
|
Map<File, String> _noteRelativePaths = {};
|
||||||
|
Map<File, String> _noteContentLower = {};
|
||||||
String? notesDirectoryPath;
|
String? notesDirectoryPath;
|
||||||
String? defaultDir;
|
String? defaultDir;
|
||||||
bool _useExternalEditor = false;
|
bool _useExternalEditor = false;
|
||||||
|
|
@ -239,7 +241,9 @@ Happy note taking! ✨
|
||||||
|
|
||||||
List<File> allNotes = [];
|
List<File> allNotes = [];
|
||||||
Map<String, DateTime> folderTimestamps = {};
|
Map<String, DateTime> folderTimestamps = {};
|
||||||
Map<File, Set<String>> extractedTags = {}; // ✅ Store extracted tags here
|
Map<File, Set<String>> extractedTags = {};
|
||||||
|
Map<File, String> extractedRelPaths = {};
|
||||||
|
Map<File, String> extractedContentLower = {};
|
||||||
|
|
||||||
void fetchNotes(Directory dir) {
|
void fetchNotes(Directory dir) {
|
||||||
final entries = dir.listSync(recursive: _includeSubdirectories);
|
final entries = dir.listSync(recursive: _includeSubdirectories);
|
||||||
|
|
@ -261,6 +265,8 @@ Happy note taking! ✨
|
||||||
|
|
||||||
final content = entry.readAsStringSync();
|
final content = entry.readAsStringSync();
|
||||||
extractedTags[entry] = _extractTags(content);
|
extractedTags[entry] = _extractTags(content);
|
||||||
|
extractedRelPaths[entry] = path.relative(entry.path, from: notesDirectoryPath!).toLowerCase();
|
||||||
|
extractedContentLower[entry] = content.toLowerCase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -286,7 +292,9 @@ Happy note taking! ✨
|
||||||
setState(() {
|
setState(() {
|
||||||
notes = allNotes;
|
notes = allNotes;
|
||||||
filteredNotes = allNotes;
|
filteredNotes = allNotes;
|
||||||
noteTags = extractedTags; // ✅ Update stored tags
|
noteTags = extractedTags;
|
||||||
|
_noteRelativePaths = extractedRelPaths;
|
||||||
|
_noteContentLower = extractedContentLower;
|
||||||
});
|
});
|
||||||
|
|
||||||
_filterNotes(); // ✅ Apply search immediately if a term is active
|
_filterNotes(); // ✅ Apply search immediately if a term is active
|
||||||
|
|
@ -329,15 +337,12 @@ Happy note taking! ✨
|
||||||
final normalizedSearch = searchText.replaceFirst(RegExp(r'^/'), '');
|
final normalizedSearch = searchText.replaceFirst(RegExp(r'^/'), '');
|
||||||
|
|
||||||
filteredNotes = notes.where((note) {
|
filteredNotes = notes.where((note) {
|
||||||
final relativePath = path.relative(note.path, from: notesDirectoryPath!).toLowerCase();
|
final relativePath = _noteRelativePaths[note] ?? '';
|
||||||
final noteTags = _extractTags(note.readAsStringSync());
|
final tags = noteTags[note] ?? {};
|
||||||
|
final content = _includeFileContent ? (_noteContentLower[note] ?? '') : '';
|
||||||
|
|
||||||
// ✅ Read file content ONLY if `Include File Content` is enabled
|
|
||||||
final content = _includeFileContent ? note.readAsStringSync().toLowerCase() : '';
|
|
||||||
|
|
||||||
// ✅ Match partial tags instead of requiring full matches (case-insensitive)
|
|
||||||
final matchesTags = searchTags.every((tag) =>
|
final matchesTags = searchTags.every((tag) =>
|
||||||
noteTags.any((noteTag) => noteTag.toLowerCase().startsWith(tag)));
|
tags.any((noteTag) => noteTag.toLowerCase().startsWith(tag)));
|
||||||
|
|
||||||
if (!_includeFileContent) {
|
if (!_includeFileContent) {
|
||||||
return relativePath.contains(normalizedSearch) && matchesTags;
|
return relativePath.contains(normalizedSearch) && matchesTags;
|
||||||
|
|
@ -439,13 +444,17 @@ Happy note taking! ✨
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newNote.existsSync()) {
|
if (!newNote.existsSync()) {
|
||||||
newNote.writeAsStringSync('# $safeTitle\n\n');
|
final newContent = '# $safeTitle\n\n';
|
||||||
|
newNote.writeAsStringSync(newContent);
|
||||||
setState(() {
|
setState(() {
|
||||||
notes.add(newNote);
|
notes.add(newNote);
|
||||||
filteredNotes.add(newNote);
|
filteredNotes.add(newNote);
|
||||||
|
noteTags[newNote] = {};
|
||||||
|
_noteRelativePaths[newNote] = path.relative(newNote.path, from: notesDirectoryPath!).toLowerCase();
|
||||||
|
_noteContentLower[newNote] = newContent.toLowerCase();
|
||||||
});
|
});
|
||||||
|
|
||||||
Navigator.push(
|
await Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => NoteEditorScreen(
|
builder: (context) => NoteEditorScreen(
|
||||||
|
|
@ -456,6 +465,7 @@ Happy note taking! ✨
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
if (context.mounted) _loadNotes();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue