import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_code_editor/flutter_code_editor.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_markdown_latex/flutter_markdown_latex.dart'; import 'package:markdown/markdown.dart' as md; import 'package:path/path.dart' as path; import 'themes/day.dart'; import 'themes/night.dart'; import 'themes/markdown.dart'; import 'codefield.dart'; class NoteEditorScreen extends StatefulWidget { final File note; final String? notesDirectoryPath; // ✅ Add this final bool isDarkMode; NoteEditorScreen( {required this.note, required this.isDarkMode, required this.notesDirectoryPath}); @override _NoteEditorScreenState createState() => _NoteEditorScreenState(); } class _NoteEditorScreenState extends State { bool isLoading = true; bool _isPreviewMode = false; // Default: Editing mode late CodeController _controller; double _fontSize = 16.0; // Default font size @override void initState() { super.initState(); _loadNoteContent(); } Future _loadNoteContent() async { String content = ""; try { content = await widget.note.readAsString(); } catch (e) { print("❌ Failed to read file: ${widget.note.path}"); } setState(() { _controller = CodeController( text: content, language: markdown, ); _controller.addListener(_saveNote); _controller.popupController.enabled = false; isLoading = false; }); } Future _saveNote() async { try { final notesDirectory = widget.notesDirectoryPath ?? widget.note.parent.path; // ✅ Use correct directory // Get the full path of the original file, preserving subfolder structure final relativeNotePath = path.relative(widget.note.path, from: notesDirectory); final newFilePath = path.join(notesDirectory, relativeNotePath); // ✅ Preserve subfolder print("📝 Attempting to save note at: $newFilePath"); final newFile = File(newFilePath); await newFile.writeAsString(_controller.text); print("✅ Successfully saved note at: $newFilePath"); } catch (e, stackTrace) { print("❌ Error saving note: ${widget.note.path}"); print("⚠️ Exception: $e"); print("🛠 Stack trace: $stackTrace"); } } void _updateFontSize(double newSize) { setState(() { _fontSize = newSize; }); } @override void dispose() { _controller.removeListener(_saveNote); _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.note.uri.pathSegments.last.replaceAll('.md', '')), actions: [ Padding( padding: EdgeInsets.symmetric(horizontal: 15), child: PopupMenuButton( icon: Icon(Icons.radio_button_checked, color: Colors.orange), onSelected: (String value) { if (value == 'Toggle Preview') { setState(() { _isPreviewMode = !_isPreviewMode; }); } }, itemBuilder: (BuildContext context) => [ PopupMenuItem( value: 'Toggle Preview', child: ListTile( leading: Icon(_isPreviewMode ? Icons.edit : Icons.preview), title: Text(_isPreviewMode ? 'Edit Mode' : 'Preview Mode'), ), ), PopupMenuItem( enabled: false, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Font Size'), StatefulBuilder( builder: (context, setState) { return Slider( value: _fontSize, min: 12.0, max: 24.0, divisions: 6, label: _fontSize.toString(), onChanged: (newSize) { setState(() { _fontSize = newSize; }); _updateFontSize(newSize); }, ); }, ), ], ), ), ], ), ), ], ), body: isLoading ? Center( child: CircularProgressIndicator()) // Show loader while initializing : _isPreviewMode ? Padding( padding: const EdgeInsets.all(16.0), child: SingleChildScrollView( child: MarkdownBody( builders: { 'latex': LatexElementBuilder( textStyle: TextStyle( color: widget.isDarkMode ? Colors.white : Colors.black)), }, extensionSet: md.ExtensionSet( [LatexBlockSyntax()], [LatexInlineSyntax()], ), data: _controller .text, // ✅ Plain Markdown without syntax highlighting selectable: true, // ✅ Allows text selection styleSheet: MarkdownStyleSheet( p: TextStyle( fontSize: _fontSize, color: widget.isDarkMode ? Colors.white : Colors.black), h1: TextStyle( fontSize: _fontSize + 8, color: widget.isDarkMode ? Colors.white : Colors.black, fontWeight: FontWeight.bold), h2: TextStyle( fontSize: _fontSize + 6, color: widget.isDarkMode ? Colors.white : Colors.black, fontWeight: FontWeight.bold), h3: TextStyle( fontSize: _fontSize + 4, color: widget.isDarkMode ? Colors.white : Colors.black, fontWeight: FontWeight.bold), code: TextStyle( fontSize: _fontSize, backgroundColor: Colors .transparent), // ✅ Disables syntax highlighting codeblockDecoration: BoxDecoration( color: Colors .transparent), // ✅ Removes background color from code blocks ), ), ), ) : Padding( padding: const EdgeInsets.all(16.0), child: CodeTheme( data: CodeThemeData( styles: widget.isDarkMode ? nightTheme : dayTheme), child: SingleChildScrollView( child: WrappedCodeField( wrap: true, controller: _controller, textStyle: TextStyle( fontSize: _fontSize, ), ), ), ), ), ); } }