This commit is contained in:
randogoth 2025-02-21 00:29:41 +02:00
parent 84c134adc4
commit 57732c7242
3 changed files with 107 additions and 51 deletions

View file

@ -97,14 +97,56 @@ class _NoteListScreenState extends State<NoteListScreen> {
_loadNotes();
searchController.addListener(() {
final text = searchController.text.trim();
if (text.startsWith(':')) {
_handleCommand(text);
} else {
_filterNotes();
_filterNotes(); // Only filter, do NOT create a note here!
}
});
}
bool _isNewNote(String title) {
final safeTitle = _sanitizeFilename(title);
return !notes.any((note) => note.uri.pathSegments.last == '$safeTitle.md');
}
Future<void> _createNewNote(String title) async {
final dir = await getApplicationDocumentsDirectory();
final notesDir = Directory('${dir.path}/notes');
if (!notesDir.existsSync()) {
notesDir.createSync(recursive: true);
}
final safeTitle = _sanitizeFilename(title);
final newNote = File('${notesDir.path}/$safeTitle.md');
if (!newNote.existsSync()) {
newNote.writeAsStringSync('# $title\n\n'); // Pre-fill with title
setState(() {
notes.add(newNote);
filteredNotes.add(newNote);
});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NoteEditorScreen(
note: newNote,
isDarkMode: widget.isDarkMode,
),
),
);
}
}
String _sanitizeFilename(String title) {
return title
.replaceAll(RegExp(r'[<>:"/\\|?*]'), '') // Remove invalid characters
.trim();
}
void _handleCommand(String text) {
switch (text) {
case ':tags':
@ -228,64 +270,77 @@ class _NoteListScreenState extends State<NoteListScreen> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: TextField(
enableInteractiveSelection: true,
autocorrect: false,
textInputAction: TextInputAction.done,
controller: searchController,
decoration: InputDecoration(
hintText: 'Search or enter a command...',
border: InputBorder.none,
title: Padding(
padding: EdgeInsets.symmetric(horizontal: 15),
child: TextField(
enableInteractiveSelection: true,
autocorrect: false,
textInputAction: TextInputAction.done,
controller: searchController,
decoration: InputDecoration(
hintText: 'Search or enter a command...',
border: InputBorder.none,
),
style: GoogleFonts.ibmPlexMono(color: Colors.grey[300]),
onSubmitted: (text) {
final trimmedText = text.trim();
if (trimmedText.isNotEmpty && _isNewNote(trimmedText)) {
_createNewNote(trimmedText);
searchController.clear(); // Clears the search field after creation
}
},
),
style: GoogleFonts.ibmPlexMono(color: Colors.grey[300]),
),
actions: [
IconButton(
icon: Icon(widget.showTags ? Icons.tag : Icons.circle_outlined),
icon: Icon(!widget.showTags ? Icons.tag : Icons.horizontal_rule),
onPressed: widget.toggleTags,
),
IconButton(
icon: Icon(Icons.brightness_6),
onPressed: () => widget.toggleTheme(!widget.isDarkMode),
),
],
),
body: ListView.builder(
itemCount: filteredNotes.length,
itemBuilder: (context, index) {
final noteFile = filteredNotes[index];
final noteContent = noteFile.readAsStringSync();
final tagSpans = _formatTags(noteContent).isNotEmpty ? _formatTags(noteContent) : [TextSpan(text: '')];
floatingActionButton: IconButton(
icon: Icon(!widget.isDarkMode ? Icons.dark_mode : Icons.light_mode),
onPressed: () => widget.toggleTheme(!widget.isDarkMode),
),
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 15),
child: ListView.builder(
itemCount: filteredNotes.length,
itemBuilder: (context, index) {
final noteFile = filteredNotes[index];
final noteContent = noteFile.readAsStringSync();
final tagSpans = _formatTags(noteContent).isNotEmpty ? _formatTags(noteContent) : [TextSpan(text: '')];
return Dismissible(
key: Key(noteFile.path),
direction: DismissDirection.endToStart,
background: Container(
color: Colors.redAccent,
alignment: Alignment.centerRight,
padding: EdgeInsets.symmetric(horizontal: 20),
child: Icon(Icons.delete, color: Colors.white),
),
onDismissed: (direction) => _deleteNote(noteFile),
child: ListTile(
title: Text(noteFile.uri.pathSegments.last.replaceAll('.md', '')),
subtitle: widget.showTags && tagSpans.isNotEmpty
? RichText(text: TextSpan(style: DefaultTextStyle.of(context).style, children: tagSpans))
: null,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NoteEditorScreen(
note: noteFile,
isDarkMode: widget.isDarkMode,
return Dismissible(
key: Key(noteFile.path),
direction: DismissDirection.endToStart,
background: Container(
color: Colors.redAccent,
alignment: Alignment.centerRight,
padding: EdgeInsets.symmetric(horizontal: 20),
child: Icon(Icons.delete, color: Colors.white),
),
onDismissed: (direction) => _deleteNote(noteFile),
child: ListTile(
title: Text(noteFile.uri.pathSegments.last.replaceAll('.md', '')),
subtitle: widget.showTags && tagSpans.isNotEmpty
? RichText(text: TextSpan(style: DefaultTextStyle.of(context).style, children: tagSpans))
: null,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NoteEditorScreen(
note: noteFile,
isDarkMode: widget.isDarkMode,
),
),
),
);
},
),
);
},
);
},
),
);
},
),
),
);
}