preserve notes

This commit is contained in:
Sarah Jamie Lewis 2022-10-08 19:26:31 -07:00
parent 6aac11934f
commit 3ed60ca3d8
5 changed files with 65 additions and 57 deletions

1
.gitignore vendored
View File

@ -43,3 +43,4 @@ app.*.map.json
/android/app/debug /android/app/debug
/android/app/profile /android/app/profile
/android/app/release /android/app/release
*.notes

View File

@ -13,7 +13,6 @@ class Editor extends StatefulWidget {
class _Editor extends State<Editor> { class _Editor extends State<Editor> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return InputListener(LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) { return InputListener(LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
//print("opening document " + path + " " + startLine.toString()); //print("opening document " + path + " " + startLine.toString());
return View(); return View();

View File

@ -31,6 +31,16 @@ class LineFile extends ChangeNotifier {
line += 1; 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 // handle the empty file case
if (backingLines.isEmpty) { if (backingLines.isEmpty) {
backingLines.insert(0, LineInfo(path, 1, "")); backingLines.insert(0, LineInfo(path, 1, ""));
@ -115,9 +125,17 @@ class LineFile extends ChangeNotifier {
void saveFile() { void saveFile() {
String content = ''; String content = '';
String notes = '';
for (var l in backingLines) { for (var l in backingLines) {
content += '${l.text}\n'; 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); File(path).writeAsStringSync(content);
} }
@ -379,6 +397,10 @@ class LineFile extends ChangeNotifier {
} }
addNote(String note) { addNote(String note) {
addNoteAtLine(cursor.line, note);
}
addNoteAtLine(int line, String note) {
var notetype = "note"; var notetype = "note";
if (note.startsWith("[incomplete]")) { if (note.startsWith("[incomplete]")) {
notetype = "incomplete"; notetype = "incomplete";
@ -386,10 +408,10 @@ class LineFile extends ChangeNotifier {
notetype = "edit"; notetype = "edit";
} }
backingLines[cursor.line - 1].annotations.add(LineAnnotation( backingLines[line - 1].annotations.add(LineAnnotation(
SourceLink( SourceLink(
path, path,
lineStart: cursor.line, lineStart: line,
), ),
"notes", "notes",
AnnotationType.note, AnnotationType.note,

View File

@ -46,7 +46,6 @@ class LineInfo extends ChangeNotifier {
List<Widget> stackElements = List.empty(growable: true); List<Widget> stackElements = List.empty(growable: true);
var charWidth = (fontSize / 2.0); var charWidth = (fontSize / 2.0);
var lineHeight = (fontSize * 1.2); var lineHeight = (fontSize * 1.2);
var usableSize = (constraints.maxWidth - gutterWidth - rightMargin - leftMargin); var usableSize = (constraints.maxWidth - gutterWidth - rightMargin - leftMargin);
@ -88,16 +87,13 @@ class LineInfo extends ChangeNotifier {
var cursorPosTop = (cursorStart! / maxCharsBeforeWrapping).floorToDouble() * lineHeight; var cursorPosTop = (cursorStart! / maxCharsBeforeWrapping).floorToDouble() * lineHeight;
var cursorPosLeft = ((cursorStart! % maxCharsBeforeWrapping) * charWidth) - charWidth / 2.0; var cursorPosLeft = ((cursorStart! % maxCharsBeforeWrapping) * charWidth) - charWidth / 2.0;
TextStyle cursorStyle = TextStyle(fontFamily: 'Iosevka', fontSize: fontSize, color: foreground, backgroundColor: Colors.transparent, letterSpacing: -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( var cursorPos =
opacity: animationController, child: Text("|", style: cursorStyle))); Positioned(top: cursorPosTop.toDouble(), left: leftMargin + cursorPosLeft.toDouble(), child: FadeTransition(opacity: animationController, child: Text("|", style: cursorStyle)));
stackElements.add( cursorPos); stackElements.add(cursorPos);
} }
var cursorOverlay = Stack(children: stackElements); var cursorOverlay = Stack(children: stackElements);
return Listener( return Listener(
onPointerDown: (event) { onPointerDown: (event) {
var inMargin = (event.localPosition.dx - gutterWidth) > usableSize; 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), margin: EdgeInsets.only(right: 1, top: 0, bottom: 0, left: 0),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Flex(direction: Axis.horizontal, mainAxisAlignment: MainAxisAlignment.start, children: sidebarContent)), child: Flex(direction: Axis.horizontal, mainAxisAlignment: MainAxisAlignment.start, children: sidebarContent)),
cursorOverlay, cursorOverlay,
])))); ]))));
}, },
); );

View File

@ -11,21 +11,18 @@ import 'line_info.dart';
class View extends StatefulWidget { class View extends StatefulWidget {
View({Key? key}) : super(key: key); View({Key? key}) : super(key: key);
@override @override
_View createState() => _View(); _View createState() => _View();
} }
class _View extends State<View> with SingleTickerProviderStateMixin { class _View extends State<View> with SingleTickerProviderStateMixin {
late AnimationController _animationController; late AnimationController _animationController;
@override @override
void initState() { void initState() {
super.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); _animationController.repeat(reverse: true);
} }
@override @override
@ -40,53 +37,47 @@ class _View extends State<View> with SingleTickerProviderStateMixin {
if (doc.backingLines.isEmpty) { if (doc.backingLines.isEmpty) {
return Center( return Center(
child: Row ( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
ElevatedButton.icon(
onPressed: () async {
String? result = await FilePicker.platform.saveFile();
if (result != null) {
ElevatedButton.icon(onPressed: () async { File(result).createSync(recursive: false);
String? result = await FilePicker.platform.saveFile( doc.openFile(result, 0);
doc.focus.requestFocus();
); } else {
// User canceled the picker
if (result != null) { }
File(result).createSync(recursive: false); },
doc.openFile(result, 0); icon: Icon(Icons.create, color: foreground),
doc.focus.requestFocus(); label: const Text("New Document"),
} else { style: ButtonStyle(backgroundColor: MaterialStateProperty.all(tabs), foregroundColor: MaterialStateProperty.all(foreground))),
// User canceled the picker SizedBox(
} width: 20,
),
ElevatedButton.icon(
}, icon: Icon(Icons.create, color: foreground), label: const Text("New Document"), onPressed: () async {
style: ButtonStyle(backgroundColor: MaterialStateProperty.all(tabs), FilePickerResult? result = await FilePicker.platform.pickFiles(
foregroundColor: MaterialStateProperty.all(foreground))), allowMultiple: false,
type: FileType.custom,
SizedBox(width: 20,), allowedExtensions: ['md', 'txt'],
);
ElevatedButton.icon(onPressed: () async { if (result != null) {
FilePickerResult? result = await FilePicker.platform.pickFiles( doc.openFile(result.files.single.path!, 0);
allowMultiple: false, } else {
type: FileType.custom, // User canceled the picker
allowedExtensions: ['md','txt'], }
); },
if (result != null) { icon: Icon(Icons.file_open, color: foreground),
doc.openFile(result.files.single.path!, 0); label: const Text("Open Document"),
} else { style: ButtonStyle(backgroundColor: MaterialStateProperty.all(tabs), foregroundColor: MaterialStateProperty.all(foreground))),
// 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 { } else {
return ScrollablePositionedList.builder( return ScrollablePositionedList.builder(
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
@ -98,8 +89,7 @@ class _View extends State<View> with SingleTickerProviderStateMixin {
return ChangeNotifierProvider.value( return ChangeNotifierProvider.value(
value: doc.backingLines[index], value: doc.backingLines[index],
builder: (lcontext, lineinfo) { builder: (lcontext, lineinfo) {
return Provider.of<LineInfo>(lcontext).build( return Provider.of<LineInfo>(lcontext).build(context, _animationController);
context, _animationController);
}); });
}); });
} }