From 27430fa5f2cf50d6074466fb18c244f23b637c73 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Sun, 9 Oct 2022 16:39:25 -0700 Subject: [PATCH] Spellchecking + Logo --- assets/subwrite-logo.png | Bin 0 -> 30765 bytes dicts/english.txt | 10004 +++++++++++++++++++++++++++++ lib/file.dart | 235 +- lib/ghostsense.dart | 36 + lib/highlighter.dart | 6 + lib/line_info.dart | 29 +- lib/outline.dart | 151 +- lib/spellcheck/spellchecker.dart | 76 + lib/view.dart | 136 +- linux/my_application.cc | 2 +- pubspec.yaml | 2 + subwrite-icon.png | Bin 0 -> 4499 bytes subwrite-logo.png | Bin 0 -> 30765 bytes test/dict_test.dart | 16 + 14 files changed, 10586 insertions(+), 107 deletions(-) create mode 100644 assets/subwrite-logo.png create mode 100644 dicts/english.txt create mode 100644 lib/ghostsense.dart create mode 100644 lib/spellcheck/spellchecker.dart create mode 100644 subwrite-icon.png create mode 100644 subwrite-logo.png create mode 100644 test/dict_test.dart diff --git a/assets/subwrite-logo.png b/assets/subwrite-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d8a6558a6201160ee831ac1bbe77b1a0f92b08ab GIT binary patch literal 30765 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 suggestions = List.empty(); + + void suggestListUp() { + suggestionIndex = (suggestionIndex - 1) % suggestions.length; + if (suggestions.length - suggestionIndex >= 14 || suggestionIndex == 0 || suggestionIndex == suggestions.length - 1) { + suggestionListController.animateTo(suggestionIndex * 13.0, duration: const Duration(milliseconds: 100), curve: Curves.decelerate); + } + notifyListeners(); + } + + void suggestListDown() { + suggestionIndex = (suggestionIndex + 1) % suggestions.length; + if (suggestions.length - suggestionIndex >= 14 || suggestionIndex == 0 || suggestionIndex == suggestions.length - 1) { + suggestionListController.animateTo(suggestionIndex * 13.0, duration: const Duration(milliseconds: 100), curve: Curves.decelerate); + } + notifyListeners(); + } + + void suggestListInsert() { + // TODO replace + } + + void loadSuggestions() { + List suggest = List.empty(growable: true); + + if (suggestLine > 0) { + backingLines[suggestLine - 1].annotations.forEach((element) { + print("${element.description} ${element.tool} $suggestCol ${element.sourceLink.colStart} ${element.sourceLink.colEnd}"); + }); + List suggestions = backingLines[suggestLine - 1] + .annotations + .where((element) => element.tool == "spellcheck") + .where((element) => suggestCol >= element.sourceLink.colStart! && suggestCol < element.sourceLink.colEnd!) + .map((e) => e.description!) + .toList(); + + if (suggestions.isNotEmpty) { + for (var spell in suggestions.first.split(":")) { + suggest.add(Suggestion("spelling", spell)); + } + this.suggestions = suggest; + notifyListeners(); + } + } + } + void openFile(String path, int startLine) { + // reset path this.path = path; + // purge backinglines... + backingLines = List.empty(growable: true); + status = "Opened $path"; File f = File(path); var line = 0; f.readAsLinesSync().forEach((text) { @@ -59,45 +141,67 @@ class LineFile extends ChangeNotifier { if (event.logicalKey == LogicalKeyboardKey.arrowLeft) { cursor.moveCursor(-1, 0, backingLines, keepAnchor: event.isShiftPressed); cursor.publishCursor(backingLines); + cancelSuggestions(); } else if (event.logicalKey == LogicalKeyboardKey.arrowRight) { cursor.moveCursor(1, 0, backingLines, keepAnchor: event.isShiftPressed); cursor.publishCursor(backingLines); + cancelSuggestions(); } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) { - cursor.moveCursor(0, -1, backingLines, keepAnchor: event.isShiftPressed); - cursor.publishCursor(backingLines); + if (showSuggestions == false) { + cursor.moveCursor(0, -1, backingLines, keepAnchor: event.isShiftPressed); + cursor.publishCursor(backingLines); + } else { + suggestListUp(); + } } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) { - cursor.moveCursor(0, 1, backingLines, keepAnchor: event.isShiftPressed); - cursor.publishCursor(backingLines); + if (showSuggestions == false) { + cursor.moveCursor(0, 1, backingLines, keepAnchor: event.isShiftPressed); + cursor.publishCursor(backingLines); + } else { + suggestListDown(); + } } else if (event.logicalKey == LogicalKeyboardKey.home) { + cancelSuggestions(); cursor.moveCursorToLineStart(); cursor.clearSelection(); cursor.publishCursor(backingLines); } else if (event.logicalKey == LogicalKeyboardKey.end) { + cancelSuggestions(); cursor.moveCursorToLineEnd(backingLines[cursor.line - 1].text.length); cursor.clearSelection(); cursor.publishCursor(backingLines); } else if (event.logicalKey == LogicalKeyboardKey.enter) { - insertLine(); - cursor.clearSelection(); - cursor.publishCursor(backingLines); + if (showSuggestions == false) { + insertLine(); + cursor.clearSelection(); + cursor.publishCursor(backingLines); + } else { + suggestListInsert(); + } } else if (event.logicalKey == LogicalKeyboardKey.tab) { insertChar(" "); cursor.publishCursor(backingLines); + cancelSuggestions(); } else if (event.logicalKey == LogicalKeyboardKey.delete) { handleDelete(); cursor.clearSelection(); cursor.publishCursor(backingLines); + cancelSuggestions(); } else if (event.logicalKey == LogicalKeyboardKey.backspace) { handleBackspace(); cursor.clearSelection(); cursor.publishCursor(backingLines); + cancelSuggestions(); } else if (event.logicalKey == LogicalKeyboardKey.escape) { showSuggestions = false; notifyListeners(); + } else if (event.logicalKey == LogicalKeyboardKey.f4) { + spellCheckAll().then((value) { + status = "spellcheck complete"; + }); } else { if (event.isControlPressed) { if (event.logicalKey == LogicalKeyboardKey.space) { - showSuggestions = true; notifyListeners(); } if (event.character != null && event.character == 's') { @@ -133,7 +237,7 @@ class LineFile extends ChangeNotifier { for (var l in backingLines) { content += '${l.text}\n'; for (var annot in l.annotations) { - if (annot.description != null) { + if (annot.description != null && annot.tool != "spellcheck") { notes += '${annot.sourceLink.lineStart}:${annot.description}\n'; } } @@ -278,6 +382,94 @@ class LineFile extends ChangeNotifier { List
sections = List.empty(growable: true); + Future spellcheck(int i) async { + var line = backingLines[i]; + line.annotations.removeWhere((element) => element.tool == "spellcheck"); + + List annotations = List.empty(growable: true); + var wordStart = 0; + var wordEnd = 0; + var lowerCase = line.text.toLowerCase(); + for (var c = 0; c < lowerCase.length; c++) { + if (lowerCase.substring(c, c + 1) == " ") { + wordEnd = c; + var annotationStart = wordStart; + var word = lowerCase.substring(wordStart, wordEnd); + wordStart = c + 1; + + if (word.endsWith(".")) { + word = word.substring(0, word.length - 1); + } + + if (word.endsWith(":")) { + word = word.substring(0, word.length - 1); + } + + if (word.endsWith(";")) { + word = word.substring(0, word.length - 1); + } + + if (word.endsWith(",")) { + word = word.substring(0, word.length - 1); + } + + // clean up quotes + word = word.replaceAll("\"", ""); + word = word.replaceAll("'", ""); + word = word.replaceAll("`", ""); + word = word.replaceAll("(", ""); + word = word.replaceAll(")", ""); + word = word.replaceAll("[", ""); + word = word.replaceAll("]", ""); + word = word.replaceAll("^", ""); + word = word.replaceAll("*", ""); + word = word.replaceAll("?", ""); + word = word.replaceAll("!", ""); + + // ignore numbers + if (word.contains(RegExp(r'[0-9]'))) { + continue; + } + + // ignore code... + if (word.contains("/") | word.contains("=") | word.contains(">") || word.contains("<") || word.contains("@") || word.contains("`") || word.contains(";")) { + continue; + } + + if (word.length < 2 || word.length > 10) { + continue; + } + + HashSet? candidates = spellchecker.candidates(word); + if (candidates == null) { + await compute(mutations2, word).then((results) { + spellchecker.dictionary.putIfAbsent(word, () => HashSet()); + results.forEach((element) { + if (spellchecker.known.contains(element)) { + spellchecker.dictionary[word]!.add(element); + } + }); + }); + } + + // Candidates should now not be null... + candidates = spellchecker.candidates(word); + if (candidates!.contains(word) == false) { + annotations.add(LineAnnotation(SourceLink("", lineStart: 0, colStart: annotationStart, colEnd: wordEnd + 1, lineEnd: 0), "spellcheck", AnnotationType.highlight, "spellcheck", + description: candidates!.join(":"))); + } + } + } + + for (var annot in annotations) { + annot.sourceLink = SourceLink(path, lineStart: i + 1, lineEnd: i + 1, colStart: annot.sourceLink.colStart, colEnd: annot.sourceLink.colEnd); + line.annotations.add(annot); + } + + notifyListeners(); + return; + } + // rebuild the annotations manager void parse() { sections.clear(); @@ -372,7 +564,9 @@ class LineFile extends ChangeNotifier { void mouseDownUpdate(int line, int col) { focus.requestFocus(); + showSuggestions = false; cursor.mouseDownUpdate(line, col, backingLines); + notifyListeners(); } void mouseDownMoveUpdate(int col) { @@ -440,4 +634,21 @@ class LineFile extends ChangeNotifier { int wordCount() { return backingLines.map((e) => e.text.trim().split(" ").length).fold(0, (previousValue, element) => previousValue + element); } + + void setSuggestIndex(int index) { + suggestionIndex = index; + notifyListeners(); + } + + Future spellCheckAll() async { + for (int i = 0; i < backingLines.length; i++) { + await spellcheck(i); + } + return Future.value(true); + } +} + +class SpellcheckerRequest { + final String text; + SpellcheckerRequest(this.text); } diff --git a/lib/ghostsense.dart b/lib/ghostsense.dart new file mode 100644 index 0000000..be6a6ae --- /dev/null +++ b/lib/ghostsense.dart @@ -0,0 +1,36 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:subwrite/theme.dart'; +import 'package:subwrite/view.dart'; +import 'file.dart'; + +class Ghostsense extends StatefulWidget { + List suggestions; + Ghostsense(this.suggestions); + @override + _Ghostsense createState() => _Ghostsense(); +} + +class _Ghostsense extends State { + @override + Widget build(BuildContext context) { + return Material( + type: MaterialType.transparency, + child: ListView.builder( + controller: Provider.of(context).suggestionListController, + physics: const BouncingScrollPhysics(), + itemCount: widget.suggestions.length, + padding: EdgeInsets.all(2.0), + itemBuilder: (BuildContext bcontext, int index) { + return Listener( + onPointerDown: (event) { + // TODO do insert... + }, + onPointerHover: (event) { + Provider.of(bcontext).setSuggestIndex(index); + }, + child: Container(color: Provider.of(context).suggestionIndex == index ? sidebarHighlight : sidebar, child: widget.suggestions[index].getWidget())); + })); + } +} diff --git a/lib/highlighter.dart b/lib/highlighter.dart index 487e840..283ef59 100644 --- a/lib/highlighter.dart +++ b/lib/highlighter.dart @@ -48,6 +48,9 @@ class Highlighter { case "code": d.color = function; break; + case "spellcheck": + d.color = variable; + d.underline = true; } decors.add(d); @@ -72,6 +75,9 @@ class Highlighter { if (d.bold = true) { style = style.copyWith(fontWeight: FontWeight.bold); } + if (d.underline = true) { + style = style.copyWith(fontStyle: FontStyle.italic); + } } } diff --git a/lib/line_info.dart b/lib/line_info.dart index c395311..6c82c4b 100644 --- a/lib/line_info.dart +++ b/lib/line_info.dart @@ -1,5 +1,6 @@ import 'dart:math'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:subwrite/theme.dart'; @@ -37,7 +38,6 @@ class LineInfo extends ChangeNotifier { return LayoutBuilder( builder: (context, constraints) { - var highlightedLine = RichText( text: TextSpan( children: spans, @@ -88,12 +88,13 @@ class LineInfo extends ChangeNotifier { var cursorPosTop = ((cursorStart! / maxCharsBeforeWrapping).floorToDouble() * lineHeight).roundToDouble(); var cursorPosLeft = max(0, (((cursorStart! % maxCharsBeforeWrapping) * charWidth) - charWidth / 2.0).roundToDouble()); 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))); + 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); - print("rebuilding line $lineNumber $idealHeight"); + //print("rebuilding line $lineNumber $idealHeight"); // print("$charWidth $lineHeight $usableSize $idealHeight ${constraints.maxWidth}"); return Listener( @@ -104,6 +105,24 @@ class LineInfo extends ChangeNotifier { if (event.down && !inMargin) { file.mouseDownUpdate(lineNumber, c.round()); } + + var set = false; + + if (event.buttons == kSecondaryMouseButton) { + for (var annot in annotations) { + if (annot.tool == "spellcheck") { + if (annot.sourceLink.colStart != null && annot.sourceLink.colEnd != null) { + if (annot.sourceLink.colStart! <= c && annot.sourceLink.colEnd! > c) { + set = true; + break; + } + } + } + } + if (set) { + Provider.of(context).showSuggestionsFor(lineNumber, c); + } + } }, onPointerMove: (event) { var inMargin = (event.localPosition.dx - gutterWidth) > usableSize; @@ -129,6 +148,7 @@ class LineInfo extends ChangeNotifier { onHover: (event) { var c = cursorFromMouse(usableSize, event.localPosition.dx - gutterWidth, event.localPosition.dy); var file = Provider.of(context, listen: false); + if (event.down) { // note should never happen because flutter only fires hover events when the mouse it up... file.mouseDownUpdate(lineNumber, c.round()); @@ -136,8 +156,7 @@ class LineInfo extends ChangeNotifier { file.mouseDownEnd(); } }, - onExit: (event) { - }, + onExit: (event) {}, child: Container( color: backgroundStyle.backgroundColor, padding: EdgeInsets.zero, diff --git a/lib/outline.dart b/lib/outline.dart index dcc29ea..1552acd 100644 --- a/lib/outline.dart +++ b/lib/outline.dart @@ -1,7 +1,10 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:subwrite/file.dart'; import 'package:subwrite/theme.dart'; +import 'package:subwrite/view.dart'; class Outline extends StatefulWidget { const Outline({super.key}); @@ -11,69 +14,107 @@ class Outline extends StatefulWidget { } class _Outline extends State { + final ScrollController controller = ScrollController(); + @override Widget build(BuildContext context) { var sections = Provider.of(context).sections; return Material( color: tabs, - child: ReorderableListView.builder( - header: Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0), - child: Column(children: [ - Row(mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.edit, - color: foreground, - ), - Text("subwrite", style: TextStyle(fontSize: 16.0, color: foreground, fontWeight: FontWeight.bold, fontFamily: "Iosevka")) - ]), - Divider( - color: foreground, - ) - ])), - footer: Padding(padding: const EdgeInsets.symmetric(vertical: 3.0, horizontal: 10.0), child: Divider(color: foreground, thickness: 4.0)), - onReorder: (int oldIndex, int newIndex) { - var doc = Provider.of(context, listen: false); - var startLine = sections[oldIndex].lineNumber; + child: LayoutBuilder(builder: (context, constraints) { + return Scrollbar( + controller: controller, + thumbVisibility: false, + trackVisibility: false, + child: ReorderableListView.builder( + scrollController: controller, + physics: AlwaysScrollableScrollPhysics(), + header: Padding( + padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0), + child: Column(children: [ + Row(mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ + // Icon( + // Icons.edit, + // color: foreground, + // ), + Image( + image: AssetImage("assets/subwrite-logo.png"), + filterQuality: FilterQuality.medium, + width: constraints.maxWidth / 3.0, + height: constraints.maxWidth / 3.0, + ) + //Text("subwrite", style: TextStyle(fontSize: 16.0, color: foreground, fontWeight: FontWeight.bold, fontFamily: "Iosevka")) + ]), + SizedBox( + height: 20, + ), + Row(mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ + TextButton( + onPressed: () { + LineFile doc = Provider.of(context); + newFile(doc); + }, + child: Text("New", style: TextStyle(fontSize: 10.0, color: foreground, fontWeight: FontWeight.bold, fontFamily: "Iosevka"))), + TextButton( + onPressed: () { + LineFile doc = Provider.of(context); + openFile(doc); + }, + child: Text("Open", style: TextStyle(fontSize: 10.0, color: foreground, fontWeight: FontWeight.bold, fontFamily: "Iosevka"))), + TextButton( + onPressed: () { + exit(0); + }, + child: Text("Exit", style: TextStyle(fontSize: 10.0, color: foreground, fontWeight: FontWeight.bold, fontFamily: "Iosevka"))), + ]), + Divider( + color: foreground, + ) + ])), + footer: Padding(padding: const EdgeInsets.symmetric(vertical: 3.0, horizontal: 10.0), child: Divider(color: foreground, thickness: 4.0)), + onReorder: (int oldIndex, int newIndex) { + var doc = Provider.of(context, listen: false); + var startLine = sections[oldIndex].lineNumber; - var endLine = doc.lines(); - for (var index = oldIndex + 1; index < sections.length; index++) { - print("${sections[oldIndex].level} > ${sections[index].level}"); - if (sections[oldIndex].level < sections[index].level) { - // sub section...skipping - } else { - endLine = sections[index].lineNumber; - break; - } - } + var endLine = doc.lines(); + for (var index = oldIndex + 1; index < sections.length; index++) { + print("${sections[oldIndex].level} > ${sections[index].level}"); + if (sections[oldIndex].level < sections[index].level) { + // sub section...skipping + } else { + endLine = sections[index].lineNumber; + break; + } + } - var newLine = newIndex >= sections.length ? doc.lines() : sections[newIndex].lineNumber; + var newLine = newIndex >= sections.length ? doc.lines() : sections[newIndex].lineNumber; - doc.moveLines(startLine, endLine, newLine); - }, - buildDefaultDragHandles: false, - itemBuilder: (BuildContext context, int index) { - return ListTile( - key: ValueKey(index), - tileColor: tabs, - title: Text( - sections[index].title.padLeft(sections[index].title.length + sections[index].level - 1, ' '), - style: TextStyle(color: foreground, fontSize: 14.0 - sections[index].level, fontFamily: "Iosevka"), - ), - onTap: () { - Provider.of(context, listen: false).scrollController.jumpTo(index: sections[index].lineNumber - 1); - }, - trailing: ReorderableDragStartListener( - index: index, - child: Icon( - Icons.drag_handle, - color: foreground, - ), - ), - ); - }, - itemCount: sections.length, - )); + doc.moveLines(startLine, endLine, newLine); + }, + buildDefaultDragHandles: false, + itemBuilder: (BuildContext context, int index) { + return ListTile( + key: ValueKey(index), + tileColor: tabs, + title: Text( + sections[index].title.padLeft(sections[index].title.length + sections[index].level - 1, ' '), + style: TextStyle(color: foreground, fontSize: 14.0 - sections[index].level, fontFamily: "Iosevka"), + ), + onTap: () { + Provider.of(context, listen: false).scrollController.jumpTo(index: sections[index].lineNumber - 1); + }, + trailing: ReorderableDragStartListener( + index: index, + child: Icon( + Icons.drag_handle, + color: foreground, + ), + ), + ); + }, + itemCount: sections.length, + )); + })); } } diff --git a/lib/spellcheck/spellchecker.dart b/lib/spellcheck/spellchecker.dart new file mode 100644 index 0000000..7ea40c8 --- /dev/null +++ b/lib/spellcheck/spellchecker.dart @@ -0,0 +1,76 @@ +import 'dart:collection'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; + +class SpellChecker { + HashMap> dictionary; + HashSet known; + + SpellChecker(this.dictionary, this.known); + + static SpellChecker load(String dictPath) { + HashMap> dictionary = HashMap(); + HashSet known = HashSet(); + File dict = File(dictPath); + print("building dictionary..."); + dict.readAsLinesSync().forEach((word) { + var lower = word.toLowerCase().trim(); + dictionary.putIfAbsent(lower, () => HashSet.from([lower])); + known.add(lower); + + mutations1(lower).forEach((element) { + dictionary.putIfAbsent(element, () => HashSet()); + dictionary[element]!.add(lower); + }); + }); + + print("builing dictionary...${dictionary.length}"); + return SpellChecker(dictionary, known); + } + + HashSet? candidates(String word) { + return dictionary[word]; + } +} + +HashSet mutations1(String word) { + // "All edits that are one edit away from `word`." + var letters = 'abcdefghijklmnopqrstuvwxyz'; + + HashSet mutations = HashSet(); + + // // delete a letter + for (int i = 0; i < word.length; i++) { + mutations.add(word.substring(0, i) + word.substring(i + 1)); + } + + // transpositions + for (int i = 0; i < word.length - 1; i++) { + mutations.add(word.substring(0, i) + word.substring(i + 1, i + 2) + word.substring(i, i + 1) + word.substring(i + 2)); + } + + // insert a letter + for (int i = 0; i < word.length; i++) { + for (var c = 0; c < 25; c++) { + mutations.add(word.substring(0, i) + letters.substring(c, c + 1) + word.substring(i)); + } + } + + // replace a letter + for (int i = 0; i < word.length; i++) { + for (var c = 0; c < 25; c++) { + mutations.add(word.substring(0, i) + letters.substring(c, c + 1) + word.substring(i + 1)); + } + } + + return mutations; +} + +HashSet mutations2(String word) { + HashSet mutations = HashSet(); + for (var e2 in mutations1(word)) { + mutations.addAll(mutations1(e2)); + } + return mutations; +} diff --git a/lib/view.dart b/lib/view.dart index 754601f..06131cf 100644 --- a/lib/view.dart +++ b/lib/view.dart @@ -6,6 +6,8 @@ import 'package:provider/provider.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:subwrite/theme.dart'; import 'file.dart'; +import 'ghostsense.dart'; +import 'highlighter.dart'; import 'line_info.dart'; class View extends StatefulWidget { @@ -31,6 +33,9 @@ class _View extends State with SingleTickerProviderStateMixin { super.dispose(); } + double x = 0.0; + double y = 0.0; + @override Widget build(BuildContext context) { LineFile doc = Provider.of(context); @@ -43,15 +48,7 @@ class _View extends State with SingleTickerProviderStateMixin { children: [ 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 - } + newFile(doc); }, icon: Icon(Icons.create, color: foreground), label: const Text("New Document"), @@ -61,16 +58,7 @@ class _View extends State with SingleTickerProviderStateMixin { ), 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 - } + openFile(doc); }, icon: Icon(Icons.file_open, color: foreground), label: const Text("Open Document"), @@ -79,21 +67,101 @@ class _View extends State with SingleTickerProviderStateMixin { ), ); } else { - - return ScrollablePositionedList.builder( - physics: const AlwaysScrollableScrollPhysics(), - itemScrollController: doc.scrollController, - itemCount: doc.lines(), - padding: EdgeInsets.zero, - minCacheExtent: 10, - addRepaintBoundaries: true, - itemBuilder: (BuildContext bcontext, int index) { - return ChangeNotifierProvider.value( - value: doc.backingLines[index], - builder: (lcontext, lineinfo) { - return Provider.of(lcontext).build(context, _animationController); - }); - }); + return MouseRegion( + onHover: (PointerEvent details) { + if (!doc.showSuggestions) { + setState(() { + x = details.localPosition.dx; + y = details.localPosition.dy; + }); + } + }, + child: Stack( + children: [ + ScrollablePositionedList.builder( + physics: const AlwaysScrollableScrollPhysics(), + itemScrollController: doc.scrollController, + itemCount: doc.lines(), + padding: EdgeInsets.zero, + minCacheExtent: 10, + addRepaintBoundaries: true, + itemBuilder: (BuildContext bcontext, int index) { + return ChangeNotifierProvider.value( + value: doc.backingLines[index], + builder: (lcontext, lineinfo) { + return Provider.of(lcontext).build(context, _animationController); + }); + }), + Visibility( + visible: doc.showSuggestions, + maintainInteractivity: false, + maintainState: false, + child: Positioned( + width: 400, + height: 200, + left: x, + top: y, + child: Container(width: 300, decoration: BoxDecoration(color: sidebarAlt, border: Border.all(color: sidebar, width: 1.0)), child: Ghostsense(doc.suggestions))), + ) + ], + )); } } } + +Future openFile(LineFile doc) 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 + } +} + +Future newFile(LineFile doc) 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 + } +} + +class Suggestion { + String classType; + String name; + + Suggestion( + this.classType, + this.name, + ); + + @override + bool operator ==(Object other) { + return other is Suggestion && hashCode == other.hashCode; + } + + @override + int get hashCode => classType.hashCode + name.hashCode; + + Widget getWidget() { + var color = function; + switch (classType) { + case "spelling": + color = header; + break; + } + + return Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + RichText(text: TextSpan(text: name, style: TextStyle(color: color, fontFamily: "Iosevka", fontSize: 11.0, fontWeight: FontWeight.bold))), + RichText(text: TextSpan(text: "dictionary", style: TextStyle(color: foreground, fontFamily: "Iosevka", fontSize: 10.0))), + ]); + } +} diff --git a/linux/my_application.cc b/linux/my_application.cc index a8a3689..1fc338c 100644 --- a/linux/my_application.cc +++ b/linux/my_application.cc @@ -49,7 +49,7 @@ static void my_application_activate(GApplication* application) { gtk_window_set_default_size(window, 1280, 720); gtk_widget_show(GTK_WIDGET(window)); - + gtk_window_set_icon_from_file(window, "./subwrite-icon.png", NULL); g_autoptr(FlDartProject) project = fl_dart_project_new(); fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); diff --git a/pubspec.yaml b/pubspec.yaml index d9210d3..25db74e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -62,6 +62,8 @@ flutter: # the material Icons class. uses-material-design: true + assets: + - assets/subwrite-logo.png fonts: - family: Iosevka diff --git a/subwrite-icon.png b/subwrite-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..83466ffcfff78a9b5e44baaca3253249d916bb16 GIT binary patch literal 4499 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