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() {
|
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) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue