In `QuillEditor` we display paragraphs using `RichText`. The height of a
`RichText` is calculated using a `TextPainter`, basically like this:
```dart
const textSpan = TextSpan(
children: [
TextSpan(text: 'Foo '),
TextSpan(text: 'Bar', style: TextStyle(fontSize: 20, height: 1)),
],
style: TextStyle(color: Colors.black, fontSize: 16),
);
final textPainter = TextPainter(text: textSpan, textDirection: TextDirection.ltr)..layout();
print('Height of textspan: ${textPainter.height}');
// Height of textspan: 20
```
Our code looks basically like this for an empty line:
```dart
const textSpan = TextSpan(
children: [TextSpan(text: '', style: TextStyle(color: Colors.black, fontSize: 20))],
style: null,
);
final textPainter = TextPainter(text: textSpan, textDirection: TextDirection.ltr)..layout();
print('Height of textspan: ${textPainter.height}');
// Height of textspan: 16
```
Now the line wrongly has the height 16 instead of 20, which cuts off the bottom
(see issue #133) from the text. To fix this, I moved the inner `TextSpan` one
layer higher.
Now the problem occurred that a line with several heights has the size of the
strut, because we enforce this size. I couldn't figure out why the strut size
is enforced, so I removed the behavior and a line with multiple sizes is now
displayed correctly.
Closes#133.
* Upgrade upgradable packages
* Apply default null-safety migrations
* Remove hashnode as a dependency and localize its functionality to the package.
Maintenance was done long time ago hence no need to wait for the update
* Localize ui package to reduce maintenance burdens
* Replace universal html with dart:html
* Remove unnecessary checks
* Fix formatting
* Migrate app to null safety
* Enable methods to be nullable
* Fix non-nullable issue with node methods
* Cast as Node
* Use universal html
* Use universal html package to bring in the ImageElement class
* Remove unused imports
* Fix imports on the editor file
* Add key to quill editor
* Remove final from the GlobalKey
* Remove final on GlobalKey
* Remove custom util implementation in favor of quiver
* Fix issue with null on token attrivute
* Remove final hashcode that is replaced by quiver functionality
* Fix merge request
* Fix hit test position in text_line.dart
* Fix null safety errors on text_selection.dart
* Fix sound null safe errors in toolbar.dart
* Import null safe file picker
* Fix issue with basic text editing and editor display
* Fix issues with basic widget rendering and editing
* Upgrade upgradable packages
* Apply default null-safety migrations
* Remove hashnode as a dependency and localize its functionality to the package.
Maintenance was done long time ago hence no need to wait for the update
* Localize ui package to reduce maintenance burdens
* Replace universal html with dart:html
* Remove unnecessary checks
* Fix formatting
* Migrate app to null safety
* Enable methods to be nullable
* Fix non-nullable issue with node methods
* Cast as Node
* Use universal html
* Use universal html package to bring in the ImageElement class
* Remove unused imports
* Fix imports on the editor file
* Add key to quill editor
* Remove final from the GlobalKey
* Remove final on GlobalKey
* Remove custom util implementation in favor of quiver
* Fix issue with null on token attrivute
* Remove final hashcode that is replaced by quiver functionality
* Fix merge request
* Fix hit test position in text_line.dart
* Fix null safety errors on text_selection.dart
* Fix sound null safe errors in toolbar.dart
* Import null safe file picker
The code change allows to override the default behaviour of clicking on
images and thus solves #90.
Now the only thing left to do is to use a `RawGestureDetector` in the
`EmbedBuilder` to deactivate the "old" behaviour (by entering the
GestureArena and win). The `embedBuilder` could look like this:
```dart
Widget embedBuilder(BuildContext context, Embed node, bool readOnly) {
return FutureBuilder<File>(
future: File('image_path.png'),
builder: (context, snapshot) {
final gestures = {
ReadDependentGestureRecognizer: GestureRecognizerFactoryWithHandlers<
ReadDependentGestureRecognizer>(
() => ReadDependentGestureRecognizer(readOnly: readOnly),
(instance) => instance
..onTapUp = ((_) => print('Test'))
)
};
return RawGestureDetector(
gestures: gestures,
child: Image.file(snapshot.data),
);
}
);
}
class ReadDependentGestureRecognizer extends TapGestureRecognizer {
ReadDependentGestureRecognizer({@required this.readOnly});
final bool readOnly;
@override
bool isPointerAllowed(PointerDownEvent event) {
if (!readOnly) {
return false;
}
return super.isPointerAllowed(event);
}
}
```
**Explanation of the code:**
When a `PointerDownEvent` is received by the `GestureBinding` a hit
test is performed to determine which `HitTestTarget` nodes are affected.
For this the (I think) element tree is traversed downwards to find
out which elements has been hit. To find out which elements were
hit, the method `hitTestSelf` and `hitTestChildren` are used. Since
the `hitTestChildren` method of `TextLine` has not been implemented
yet, `false` was always returned, which is why the hit test
never arrived at the `embedBuilder`. With the code change, the hit is
passed on and can be processed correctly in the embed.
Additionally I removed the class `_TransparentTapGestureRecognizer`,
because this class always accepted the gesture, even if the recognizer
lost in the arena.