better tag search
This commit is contained in:
parent
f77a66d5d8
commit
004d2d9e82
1 changed files with 82 additions and 42 deletions
|
|
@ -194,45 +194,74 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
|||
}
|
||||
|
||||
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(() {
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
List<InlineSpan> _formatTags(String content) {
|
||||
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)) {
|
||||
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;
|
||||
if (tag.startsWith('#')) tagColor = Colors.pinkAccent;
|
||||
if (tag.startsWith('+')) tagColor = Colors.cyan;
|
||||
if (tag.startsWith('@')) tagColor = Colors.orange;
|
||||
|
||||
spans.add(TextSpan(
|
||||
text: tag + ' ',
|
||||
style: TextStyle(color: tagColor, fontWeight: FontWeight.bold)));
|
||||
}
|
||||
return spans;
|
||||
return TextSpan(
|
||||
text: "$tag ",
|
||||
style: TextStyle(color: tagColor, fontWeight: FontWeight.bold),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
void _createNewNote(String title) async {
|
||||
|
|
@ -591,22 +620,33 @@ class _NoteListScreenState extends State<NoteListScreen> {
|
|||
child: ListTile(
|
||||
title:
|
||||
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: [
|
||||
path.relative(path.dirname(noteFile.path), from: notesDirectoryPath!) != "."
|
||||
? Text(
|
||||
if (path.relative(path.dirname(noteFile.path), from: notesDirectoryPath!) != ".")
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 8),
|
||||
child: Text(
|
||||
path.relative(path.dirname(noteFile.path), from: notesDirectoryPath!),
|
||||
style: TextStyle(color: Colors.blueGrey),
|
||||
)
|
||||
: Text(""),
|
||||
widget.showTags && tagSpans.isNotEmpty
|
||||
? RichText(
|
||||
),
|
||||
),
|
||||
if (widget.showTags && hasEnoughSpace && tagSpans.isNotEmpty)
|
||||
Expanded(
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
style: DefaultTextStyle.of(context).style,
|
||||
children: tagSpans)
|
||||
)
|
||||
: Text("")
|
||||
children: tagSpans,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis, // Prevents overflow errors
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
onTap: () async {
|
||||
if (_useExternalEditor) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue