better tag search

This commit is contained in:
randogoth 2025-02-22 15:58:17 +02:00
parent f77a66d5d8
commit 004d2d9e82

View file

@ -194,45 +194,74 @@ class _NoteListScreenState extends State<NoteListScreen> {
} }
void _filterNotes() { void _filterNotes() {
final query = searchController.text.trim().toLowerCase(); final query = searchController.text.trim();
if (query.isEmpty) {
setState(() {
filteredNotes = notes;
});
return;
}
final List<String> words = query.split(RegExp(r'\s+')); // Split by spaces
final List<String> terms = [];
final List<String> tags = [];
for (final word in words) {
if (word.startsWith('#') || word.startsWith('+') || word.startsWith('@')) {
tags.add(word.toLowerCase());
} else {
terms.add(word.toLowerCase());
}
}
setState(() { setState(() {
if (query.startsWith('/')) {
// Extract subfolder path and search term
final parts = query.split('/');
final subfolderPath = parts.sublist(1, parts.length - 1).join('/');
final searchTerm = parts.last;
filteredNotes = notes.where((note) {
final relativePath = path.relative(note.path, from: notesDirectoryPath!);
return relativePath.startsWith(subfolderPath) &&
(relativePath.contains(searchTerm) || note.readAsStringSync().toLowerCase().contains(searchTerm));
}).toList();
} else {
// Default search across all notes
filteredNotes = notes.where((note) { filteredNotes = notes.where((note) {
final content = note.readAsStringSync().toLowerCase(); final content = note.readAsStringSync().toLowerCase();
return note.uri.pathSegments.last.toLowerCase().contains(query) || content.contains(query); final filename = note.uri.pathSegments.last.toLowerCase();
// Check if all terms are found in filename or content
final bool matchesTerms = terms.isEmpty ||
terms.every((term) => filename.contains(term) || content.contains(term));
// Check if all tags are found in content
final bool matchesTags = tags.isEmpty ||
tags.every((tag) => content.contains(tag));
return matchesTerms && matchesTags;
}).toList(); }).toList();
}
}); });
} }
List<InlineSpan> _formatTags(String content) { List<InlineSpan> _formatTags(String content) {
final tagPattern = RegExp(r'([#@+][a-zA-Z0-9_]+)'); final tagPattern = RegExp(r'([#@+][a-zA-Z0-9_]+)');
final List<InlineSpan> spans = []; final Set<String> tagSet = {}; // Avoid duplicate tags
for (final match in tagPattern.allMatches(content)) { for (final match in tagPattern.allMatches(content)) {
final tag = match.group(0)!; tagSet.add(match.group(0)!);
}
// Sort tags: +tags before @tags before #tags
final sortedTags = tagSet.toList()
..sort((a, b) {
if (a.startsWith('+') && !b.startsWith('+')) return -1;
if (b.startsWith('+') && !a.startsWith('+')) return 1;
if (a.startsWith('@') && !b.startsWith('@')) return -1;
if (b.startsWith('@') && !a.startsWith('@')) return 1;
return a.compareTo(b); // Default alphabetical order
});
return sortedTags.map((tag) {
Color tagColor = Colors.white; Color tagColor = Colors.white;
if (tag.startsWith('#')) tagColor = Colors.pinkAccent; if (tag.startsWith('#')) tagColor = Colors.pinkAccent;
if (tag.startsWith('+')) tagColor = Colors.cyan; if (tag.startsWith('+')) tagColor = Colors.cyan;
if (tag.startsWith('@')) tagColor = Colors.orange; if (tag.startsWith('@')) tagColor = Colors.orange;
spans.add(TextSpan( return TextSpan(
text: tag + ' ', text: "$tag ",
style: TextStyle(color: tagColor, fontWeight: FontWeight.bold))); style: TextStyle(color: tagColor, fontWeight: FontWeight.bold),
} );
return spans; }).toList();
} }
void _createNewNote(String title) async { void _createNewNote(String title) async {
@ -591,22 +620,33 @@ class _NoteListScreenState extends State<NoteListScreen> {
child: ListTile( child: ListTile(
title: title:
Text(noteFile.uri.pathSegments.last.replaceAll('.md', '')), Text(noteFile.uri.pathSegments.last.replaceAll('.md', '')),
subtitle: Row( subtitle: LayoutBuilder(
builder: (context, constraints) {
final bool hasEnoughSpace = constraints.maxWidth > 200; // Adjust as needed
return Row(
children: [ children: [
path.relative(path.dirname(noteFile.path), from: notesDirectoryPath!) != "." if (path.relative(path.dirname(noteFile.path), from: notesDirectoryPath!) != ".")
? Text( Padding(
padding: EdgeInsets.only(right: 8),
child: Text(
path.relative(path.dirname(noteFile.path), from: notesDirectoryPath!), path.relative(path.dirname(noteFile.path), from: notesDirectoryPath!),
style: TextStyle(color: Colors.blueGrey), style: TextStyle(color: Colors.blueGrey),
) ),
: Text(""), ),
widget.showTags && tagSpans.isNotEmpty if (widget.showTags && hasEnoughSpace && tagSpans.isNotEmpty)
? RichText( Expanded(
child: RichText(
text: TextSpan( text: TextSpan(
style: DefaultTextStyle.of(context).style, style: DefaultTextStyle.of(context).style,
children: tagSpans) children: tagSpans,
) ),
: Text("") overflow: TextOverflow.ellipsis, // Prevents overflow errors
),
),
], ],
);
},
), ),
onTap: () async { onTap: () async {
if (_useExternalEditor) { if (_useExternalEditor) {