diff --git a/.gitignore b/.gitignore index faba45b..7c70847 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release +*.notes \ No newline at end of file diff --git a/lib/editor.dart b/lib/editor.dart index 999f096..6c455fa 100644 --- a/lib/editor.dart +++ b/lib/editor.dart @@ -13,7 +13,6 @@ class Editor extends StatefulWidget { class _Editor extends State { @override Widget build(BuildContext context) { - return InputListener(LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) { //print("opening document " + path + " " + startLine.toString()); return View(); diff --git a/lib/file.dart b/lib/file.dart index 4127e94..38e4f23 100644 --- a/lib/file.dart +++ b/lib/file.dart @@ -31,6 +31,16 @@ class LineFile extends ChangeNotifier { line += 1; }); + File notesFile = File("$path.subwrite.notes"); + if (notesFile.existsSync()) { + notesFile.readAsLinesSync().forEach((notetext) { + var parts = notetext.split(":"); + var line = int.parse(parts[0]); + var note = parts.sublist(1).join(":"); + addNoteAtLine(line, note); + }); + } + // handle the empty file case if (backingLines.isEmpty) { backingLines.insert(0, LineInfo(path, 1, "")); @@ -115,9 +125,17 @@ class LineFile extends ChangeNotifier { void saveFile() { String content = ''; + String notes = ''; for (var l in backingLines) { content += '${l.text}\n'; + for (var annot in l.annotations) { + if (annot.description != null) { + notes += '${annot.sourceLink.lineStart}:${annot.description}\n'; + } + } } + + File("$path.subwrite.notes").writeAsStringSync(notes); File(path).writeAsStringSync(content); } @@ -379,6 +397,10 @@ class LineFile extends ChangeNotifier { } addNote(String note) { + addNoteAtLine(cursor.line, note); + } + + addNoteAtLine(int line, String note) { var notetype = "note"; if (note.startsWith("[incomplete]")) { notetype = "incomplete"; @@ -386,10 +408,10 @@ class LineFile extends ChangeNotifier { notetype = "edit"; } - backingLines[cursor.line - 1].annotations.add(LineAnnotation( + backingLines[line - 1].annotations.add(LineAnnotation( SourceLink( path, - lineStart: cursor.line, + lineStart: line, ), "notes", AnnotationType.note, diff --git a/lib/line_info.dart b/lib/line_info.dart index 1890ac8..03ec498 100644 --- a/lib/line_info.dart +++ b/lib/line_info.dart @@ -46,7 +46,6 @@ class LineInfo extends ChangeNotifier { List stackElements = List.empty(growable: true); - var charWidth = (fontSize / 2.0); var lineHeight = (fontSize * 1.2); var usableSize = (constraints.maxWidth - gutterWidth - rightMargin - leftMargin); @@ -88,16 +87,13 @@ class LineInfo extends ChangeNotifier { var cursorPosTop = (cursorStart! / maxCharsBeforeWrapping).floorToDouble() * lineHeight; var cursorPosLeft = ((cursorStart! % maxCharsBeforeWrapping) * charWidth) - charWidth / 2.0; TextStyle cursorStyle = TextStyle(fontFamily: 'Iosevka', fontSize: fontSize, color: foreground, backgroundColor: Colors.transparent, letterSpacing: -2.0); - var cursorPos = Positioned(top: cursorPosTop.toDouble(), left: leftMargin+cursorPosLeft.toDouble(), child: FadeTransition( - opacity: animationController, child: Text("|", style: cursorStyle))); - stackElements.add( cursorPos); + var cursorPos = + Positioned(top: cursorPosTop.toDouble(), left: leftMargin + cursorPosLeft.toDouble(), child: FadeTransition(opacity: animationController, child: Text("|", style: cursorStyle))); + stackElements.add(cursorPos); } - var cursorOverlay = Stack(children: stackElements); - - return Listener( onPointerDown: (event) { var inMargin = (event.localPosition.dx - gutterWidth) > usableSize; @@ -158,7 +154,7 @@ class LineInfo extends ChangeNotifier { margin: EdgeInsets.only(right: 1, top: 0, bottom: 0, left: 0), alignment: Alignment.centerLeft, child: Flex(direction: Axis.horizontal, mainAxisAlignment: MainAxisAlignment.start, children: sidebarContent)), - cursorOverlay, + cursorOverlay, ])))); }, ); diff --git a/lib/view.dart b/lib/view.dart index 2d03864..6ef9b03 100644 --- a/lib/view.dart +++ b/lib/view.dart @@ -11,21 +11,18 @@ import 'line_info.dart'; class View extends StatefulWidget { View({Key? key}) : super(key: key); - @override _View createState() => _View(); } class _View extends State with SingleTickerProviderStateMixin { - late AnimationController _animationController; @override void initState() { super.initState(); - _animationController = AnimationController(vsync: this, duration: const Duration(milliseconds: 300)); + _animationController = AnimationController(vsync: this, duration: const Duration(milliseconds: 300)); _animationController.repeat(reverse: true); - } @override @@ -40,53 +37,47 @@ class _View extends State with SingleTickerProviderStateMixin { if (doc.backingLines.isEmpty) { return Center( - child: Row ( + child: Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ + ElevatedButton.icon( + onPressed: () async { + String? result = await FilePicker.platform.saveFile(); - - ElevatedButton.icon(onPressed: () async { - String? result = await FilePicker.platform.saveFile( - - ); - - if (result != null) { - File(result).createSync(recursive: false); - doc.openFile(result, 0); - doc.focus.requestFocus(); - } else { - // User canceled the picker - } - - - }, icon: Icon(Icons.create, color: foreground), label: const Text("New Document"), - style: ButtonStyle(backgroundColor: MaterialStateProperty.all(tabs), - foregroundColor: MaterialStateProperty.all(foreground))), - - SizedBox(width: 20,), - - ElevatedButton.icon(onPressed: () async { - FilePickerResult? result = await FilePicker.platform.pickFiles( - allowMultiple: false, - type: FileType.custom, - allowedExtensions: ['md','txt'], - ); - if (result != null) { - doc.openFile(result.files.single.path!, 0); - } else { - // User canceled the picker - } - - - }, icon: Icon(Icons.file_open, color: foreground), label: const Text("Open Document"), - style: ButtonStyle(backgroundColor: MaterialStateProperty.all(tabs), - foregroundColor: MaterialStateProperty.all(foreground))), - + if (result != null) { + File(result).createSync(recursive: false); + doc.openFile(result, 0); + doc.focus.requestFocus(); + } else { + // User canceled the picker + } + }, + icon: Icon(Icons.create, color: foreground), + label: const Text("New Document"), + style: ButtonStyle(backgroundColor: MaterialStateProperty.all(tabs), foregroundColor: MaterialStateProperty.all(foreground))), + SizedBox( + width: 20, + ), + ElevatedButton.icon( + onPressed: () async { + FilePickerResult? result = await FilePicker.platform.pickFiles( + allowMultiple: false, + type: FileType.custom, + allowedExtensions: ['md', 'txt'], + ); + if (result != null) { + doc.openFile(result.files.single.path!, 0); + } else { + // User canceled the picker + } + }, + icon: Icon(Icons.file_open, color: foreground), + label: const Text("Open Document"), + style: ButtonStyle(backgroundColor: MaterialStateProperty.all(tabs), foregroundColor: MaterialStateProperty.all(foreground))), ], ), ); - } else { return ScrollablePositionedList.builder( physics: const AlwaysScrollableScrollPhysics(), @@ -98,8 +89,7 @@ class _View extends State with SingleTickerProviderStateMixin { return ChangeNotifierProvider.value( value: doc.backingLines[index], builder: (lcontext, lineinfo) { - return Provider.of(lcontext).build( - context, _animationController); + return Provider.of(lcontext).build(context, _animationController); }); }); }