diff --git a/lib/note_list.dart b/lib/note_list.dart index ca31da6..7bdd260 100644 --- a/lib/note_list.dart +++ b/lib/note_list.dart @@ -194,45 +194,74 @@ class _NoteListScreenState extends State { } void _filterNotes() { - final query = searchController.text.trim().toLowerCase(); + final query = searchController.text.trim(); + if (query.isEmpty) { + setState(() { + filteredNotes = notes; + }); + return; + } + + final List words = query.split(RegExp(r'\s+')); // Split by spaces + final List terms = []; + final List 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 content = note.readAsStringSync().toLowerCase(); + final filename = note.uri.pathSegments.last.toLowerCase(); - 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); - }).toList(); - } + // 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 _formatTags(String content) { final tagPattern = RegExp(r'([#@+][a-zA-Z0-9_]+)'); - final List spans = []; + final Set 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,23 +620,34 @@ class _NoteListScreenState extends State { child: ListTile( title: Text(noteFile.uri.pathSegments.last.replaceAll('.md', '')), - subtitle: Row( - children: [ - path.relative(path.dirname(noteFile.path), from: notesDirectoryPath!) != "." - ? Text( - path.relative(path.dirname(noteFile.path), from: notesDirectoryPath!), - style: TextStyle(color: Colors.blueGrey), - ) - : Text(""), - widget.showTags && tagSpans.isNotEmpty - ? RichText( - text: TextSpan( - style: DefaultTextStyle.of(context).style, - children: tagSpans) - ) - : Text("") - ], - ), + subtitle: LayoutBuilder( + builder: (context, constraints) { + final bool hasEnoughSpace = constraints.maxWidth > 200; // Adjust as needed + + return Row( + children: [ + 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), + ), + ), + if (widget.showTags && hasEnoughSpace && tagSpans.isNotEmpty) + Expanded( + child: RichText( + text: TextSpan( + style: DefaultTextStyle.of(context).style, + children: tagSpans, + ), + overflow: TextOverflow.ellipsis, // Prevents overflow errors + ), + ), + ], + ); + }, + ), onTap: () async { if (_useExternalEditor) { // Open with system's default editor