Closed matt3o closed 1 week ago
In the optimal case I would not have to modify the document itself, but only the visual display but no idea if that is possible. So I far I experimented with editing the document.
To make this we will need to add a way to create a connection between a portion of a text, and the custom embed. Then, we will need draw that Embed Objet at the same offset of the that line to make possible something similar... This is not a thing that can be do it on one day.
I'll add it to my todo list.
@CatHood0 Many thanks for the quick response and for taking on the idea :) If I can help you, just write me.
Another but kind of related question: Is there generally any kind of position encoding in the document? I was wondering how difficult it would be to construct a clickable list of contents based on the headings. I know how to extract the headings, but I'm not sure how to locate their position in the document. String matching would work but that sounds super expensive and hacky..
Another but kind of related question: Is there generally any kind of position encoding in the document? I was wondering how difficult it would be to construct a clickable list of contents based on the headings. I know how to extract the headings, but I'm not sure how to locate their position in the document. String matching would work but that sounds super expensive and hacky..
Yes, you can, however, you would need to have access to the document nodes. These nodes contain the local offset within themselves (this is because a node can be a Line
, or a Block
) and a global offset called documentOffset
, which as its name indicates, would actually be the position where said node is located in the document. Now, how do we get said nodes?
I think you should try using the following code:
final QuillController _controller = QuillController.basic();
// get the ChildQuery
final query = _controller.document.queryChild(_controller.selection.baseOffset);
// get the node (can be a Line or a Block)
final Node? node = query.node;
// a way to get the global offset of this node
final int offsetChild = query.offset;
// another way to get the global offset of this node
final int? nodeGlobalOffset = node?.documentOffset;
This is what I went with, it is working for now but I think it's crazy hacky. I am manually iterating through the deltas searching for header elements, then parsing the previous elements for the actual text of the header. Computing can be offloaded via an isolate and I debounced the function as to not call the update too often.
```dart
Future>> updateHeadings(UpdateHeadingsParams params) async {
final document = params.document;
final List
Great tip, that simplifies it a lot:
```dart
Future>> updateHeadings(UpdateHeadingsParams params) async {
final document = params.document;
final Root root = document.root;
final List
@CatHood0 Is there any way to get the current quill controller offset without actually clicking somewhere (either first line or from hover?)? I tried to get it from the scrollController but no chance, since I don't know the association between ScrollController position and the actual offset in the document. Together with the code above that would actually be enough to implement what I had in my mind..
You can use TextSelection
from the QuillController
:
final currentSelection = quillController.selection.baseOffset;
@CatHood0 Yes but that triggers / updates only if the user clicked somewhere in the document, or am I using the wrong listener? I want to have a listener which works based on what is visible / where the ScrollController is positioned. Then I could sync the editor position with the comment widget
Listening to updates of the scroll controller:
print("Scroll offset: ${widget.scrollController.offset}");
print("Quill Controller position: ${widget.controller.selection.baseOffset}");
Quill Controller position: 1
Scroll offset: 3734
Quill Controller position: 1
Scroll offset: 3834
Quill Controller position: 1
Scroll offset: 3934
Quill Controller position: 1
Scroll offset: 4134
Also the scroll controller offset and the quill controller position are not the same for the same position which makes it even more confusing
What you're trying to do sounds like something very complex. I don't know how to help you with it. Listening to the ScrollController events can be effective, but it's still very difficult.
I would recommend you create your own fork of Flutter Quill and modify it to your liking so that it allows you to get the content you want based on what is displayed on the screen.
The file that contains the QuillEditor
itself has several functions that are responsible for finding the corresponding node based on the offset found on the screen.
@CatHood0 Sad but fair, thanks for all your help then! I'll close this topic
In case anyone else needs it, here is my sample code for adding comments to flutter quill:
```dart
// screens/quill_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'quill_screen_sample_data.dart';
import 'comment_block.dart';
import 'package:flutter_quill/quill_delta.dart';
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'dart:collection' show LinkedList;
import 'dart:convert';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: QuillEditorScreen(),
);
}
}
Document filterDocument(Document originalDocument, bool showComments) {
// Extract the deltas from the original document.
final filteredDelta = Delta();
for (var op in originalDocument.toDelta().toList()) {
if (op.isNotPlain) {
// Check if the embedded block is a comment
if (op.value is Map && op.value.containsKey(NotesBlockEmbed.noteType)) {
if (showComments) {
// Include the notes embed if we want comments
filteredDelta.push(op);
}
}
} else {
// Include regular text only if we do NOT want comments
if (!showComments) {
filteredDelta.push(op);
}
}
}
// If filteredDelta is empty, add an empty paragraph to avoid errors
if (filteredDelta.isEmpty) {
filteredDelta.push(Operation.insert('\n'));
}
return Document.fromDelta(filteredDelta);
}
String makeNewlinesVisible(String inputString) {
return inputString.replaceAll(RegExp(r'\r?\n'), '⏎');
}
class UpdateHeadingsParams {
final Document document;
final List>> updateHeadings(UpdateHeadingsParams params) async {
final document = params.document;
final Root root = document.root;
final List
Is there an existing issue for this?
Use case
I have added inline comments similar to what is described in the docs, see https://github.com/singerdmx/flutter-quill/blob/master/doc/custom_embed_blocks.md including an icon to add a new comment and icon to switch between comment icon and full text comment. Now as another option, I want to display these notes on the right sides in a second column and this time I want to show only the comments, kind of like the comment bar in word. I tried around a little bit but not get it working so far. Any help would be very appreciated!
Full comment including the text:
Inline comment marker:
Proposal
A scrollable second widget which only shows the full text comments and not the normal text. Also it should be sychronized with the scrollstate of the main editor (which can probably be achieved by sharing the ScrollController I guess).