preserve notes
This commit is contained in:
parent
6aac11934f
commit
3ed60ca3d8
|
@ -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
|
|
@ -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();
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
]))));
|
]))));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -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);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue