From 185a1c62e921f368c0fe7b77c6601847d04cd968 Mon Sep 17 00:00:00 2001 From: randogoth Date: Fri, 21 Feb 2025 18:16:17 +0200 Subject: [PATCH] markdown and latex preview --- lib/main.dart | 2 +- lib/note_editor.dart | 125 +++++++++++++++++++++++++++---------------- pubspec.lock | 112 ++++++++++++++++++++++++++++++++++++++ pubspec.yaml | 2 + 4 files changed, 195 insertions(+), 46 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 53170cd..324f718 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -309,7 +309,7 @@ class _NoteListScreenState extends State { padding: EdgeInsets.symmetric(horizontal: 15), child: PopupMenuButton( icon: Icon( - Icons.trip_origin, + Icons.radio_button_checked, color: Colors.orange ), // Menu button (⋮) onSelected: (String value) { diff --git a/lib/note_editor.dart b/lib/note_editor.dart index c0ba362..03652ef 100644 --- a/lib/note_editor.dart +++ b/lib/note_editor.dart @@ -1,5 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_code_editor/flutter_code_editor.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:markdown/markdown.dart' as md; +import 'package:flutter_markdown_latex/flutter_markdown_latex.dart'; import 'themes/day.dart'; import 'themes/night.dart'; import 'themes/markdown.dart'; @@ -16,6 +19,7 @@ class NoteEditorScreen extends StatefulWidget { } class _NoteEditorScreenState extends State { + bool _isPreviewMode = false; // Default: Editing mode late CodeController _controller; double _fontSize = 16.0; // Default font size @@ -61,59 +65,90 @@ class _NoteEditorScreenState extends State { appBar: AppBar( title: Text(widget.note.uri.pathSegments.last.replaceAll('.md', '')), actions: [ - PopupMenuButton( - icon: Icon(Icons.more_vert), // Menu button (⋮) - onSelected: (String value) { - if (value == 'Toggle Theme') { - setState(() { - widget.isDarkMode = !widget.isDarkMode; - }); - } - }, - itemBuilder: (BuildContext context) => [ - PopupMenuItem( - value: 'Toggle Theme', - child: ListTile( - leading: Icon( - widget.isDarkMode ? Icons.light_mode : Icons.dark_mode, - ), - title: Text( - widget.isDarkMode ? 'Switch to Light Mode' : 'Switch to Dark Mode', + 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); - }, - ); - }, - ), - ], + 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: _controller == null ? Center(child: CircularProgressIndicator()) + : _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( diff --git a/pubspec.lock b/pubspec.lock index 4fc1918..263d3dc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + args: + dependency: transitive + description: + name: args + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + url: "https://pub.dev" + source: hosted + version: "2.6.0" async: dependency: transitive description: @@ -126,6 +134,38 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.0" + flutter_markdown: + dependency: "direct main" + description: + name: flutter_markdown + sha256: e7bbc718adc9476aa14cfddc1ef048d2e21e4e8f18311aaac723266db9f9e7b5 + url: "https://pub.dev" + source: hosted + version: "0.7.6+2" + flutter_markdown_latex: + dependency: "direct main" + description: + name: flutter_markdown_latex + sha256: "839e76a84abb3632ffcebbd450cf93c7e9894af65622527d23f0084cee1bfd04" + url: "https://pub.dev" + source: hosted + version: "0.3.4" + flutter_math_fork: + dependency: transitive + description: + name: flutter_math_fork + sha256: "284bab89b2fbf1bc3a0baf13d011c1dd324d004e35d177626b77f2fc056366ac" + url: "https://pub.dev" + source: hosted + version: "0.7.3" + flutter_svg: + dependency: transitive + description: + name: flutter_svg + sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b + url: "https://pub.dev" + source: hosted + version: "2.0.17" flutter_test: dependency: "direct dev" description: flutter @@ -216,6 +256,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.1.1" + markdown: + dependency: transitive + description: + name: markdown + sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1" + url: "https://pub.dev" + source: hosted + version: "7.3.0" matcher: dependency: transitive description: @@ -248,6 +296,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" path: dependency: transitive description: @@ -256,6 +312,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" path_provider: dependency: "direct main" description: @@ -304,6 +368,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" platform: dependency: transitive description: @@ -320,6 +392,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + provider: + dependency: transitive + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" scrollable_positioned_list: dependency: transitive description: @@ -461,6 +541,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.4" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de" + url: "https://pub.dev" + source: hosted + version: "1.1.18" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad" + url: "https://pub.dev" + source: hosted + version: "1.1.16" vector_math: dependency: transitive description: @@ -493,6 +597,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" sdks: dart: ">=3.6.0 <4.0.0" flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml index 4259a59..b1db1d0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,8 @@ dependencies: path_provider: ^2.1.5 flutter_highlight: ^0.7.0 flutter_code_editor: ^0.3.2 + flutter_markdown: ^0.7.6+2 + flutter_markdown_latex: ^0.3.4 dev_dependencies: flutter_test: