fleather-editor / fleather

Soft and gentle rich text editing for Flutter applications.
https://fleather-editor.github.io
Other
192 stars 34 forks source link

Can we have easier to work with listeners, max lenght and textformating on changes made easier? #333

Open ember11498 opened 4 months ago

ember11498 commented 4 months ago

Can we please have an easy way to set a maximum text length or at least make the overflow text (text after the max length) be colored background red or something. I have tried controller.addlistener and controller.document.changes.listen but it's not easy at all, there is always some thrown exception or odd behavior.

I have played with it for several hours and I could not get what I want which ultimately is to set maximum length to 350 characters and all characters between 300 and 350 should be background red.

My problems were, when I try to set max characters by replacingtext it indeed works but it throws an exception and loses focus. And when I try to set the background it enters in an infinite loop of never stopping triggering the listen stream

Kontrano commented 4 months ago

This would definatly be a nice feature

Amir-P commented 4 months ago

Thanks for opening the issue. These are indeed nice features to have. Recently, I've been thinking about providing a way to add background/foreground decorations but haven't started working on it yet. I will be busy for the next week or two but after that I will definitely start working on some of these missing features. In the mean time, feel free to contribute if you want. @Kontrano @ember11498

ember11498 commented 4 months ago

@Amir-P just as an example I tried this code:

_controller.addListener(() {
  if (_controller.document.length > threshold) {
    final overflow = _controller.document.length - threshold; 
    _controller.replaceText(threshold - 1, overflow, "");
  }
});

And despite it working it throws an exception and the bar disappears/loses focus. I got this error:

════════ Exception caught by rendering library ═════════════════════════════════
The following assertion was thrown during paint():
No child at position TextPosition(offset: 300, affinity: TextAffinity.downstream)
'package:fleather/src/rendering/editable_box.dart':
Failed assertion: line 245 pos 12: 'targetChild != null'

The relevant error-causing widget was:
    FleatherField FleatherField:file:///C:/src/projects/plotalot/client/lib/infrastructure/text_editor/fleather_editor.dart:106:26

When the exception was thrown, this was the stack:
#2      RenderEditableContainerBox.childAtPosition (package:fleather/src/rendering/editable_box.dart:245:12)
editable_box.dart:245
#3      RenderEditor._getOffsetForCaret (package:fleather/src/rendering/editor.dart:315:19)
editor.dart:315
#4      RenderEditor._updateSelectionExtentsVisibility (package:fleather/src/rendering/editor.dart:291:25)
editor.dart:291
#5      RenderEditor.paint (package:fleather/src/rendering/editor.dart:632:5)
editor.dart:632
#6      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3237:7)
object.dart:3237
#7      PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13)
object.dart:250
#8      RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:130:13)
proxy_box.dart:130
#9      PaintingContext.pushLayer (package:flutter/src/rendering/object.dart:486:12)
object.dart:486
#10     RenderLeaderLayer.paint (package:flutter/src/rendering/proxy_box.dart:4756:13)
proxy_box.dart:4756
#11     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3237:7)
object.dart:3237
#12     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13)
object.dart:250
#13     _RenderSingleChildViewport.paint.paintContents (package:fleather/src/widgets/single_child_scroll_view.dart:255:17)
single_child_scroll_view.dart:255
#14     _RenderSingleChildViewport.paint (package:fleather/src/widgets/single_child_scroll_view.dart:269:9)
single_child_scroll_view.dart:269
#15     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3237:7)
object.dart:3237
#16     PaintingContext._repaintCompositedChild (package:flutter/src/rendering/object.dart:166:11)
object.dart:166
#17     PaintingContext.repaintCompositedChild (package:flutter/src/rendering/object.dart:109:5)
object.dart:109
#18     PipelineOwner.flushPaint (package:flutter/src/rendering/object.dart:1182:31)
object.dart:1182
#19     PipelineOwner.flushPaint (package:flutter/src/rendering/object.dart:1192:15)
object.dart:1192
#20     RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:584:23)
binding.dart:584
#21     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:991:13)
binding.dart:991
#22     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:448:5)
binding.dart:448
#23     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1386:15)
#24     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1311:9)
binding.dart:1311
#25     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1169:5)
binding.dart:1169
#26     _invoke (dart:ui/hooks.dart:312:13)
hooks.dart:312
#27     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:399:5)
platform_dispatcher.dart:399
#28     _drawFrame (dart:ui/hooks.dart:283:31)
hooks.dart:283
(elided 2 frames from class _AssertionError)

The following RenderObject was being processed when the exception was fired: RenderEditor#baed4 relayoutBoundary=up21
    parentData: <none> (can use size)
    constraints: BoxConstraints(w=392.7, 0.0<=h<=Infinity)
    size: Size(392.7, 163.0)
    child 1: RenderEditableTextLine#ddea0 relayoutBoundary=up22
        parentData: offset=Offset(8.0, 0.0) (can use size)
        constraints: BoxConstraints(w=376.7, 0.0<=h<=Infinity)
        size: Size(376.7, 163.0)
        body: RenderParagraphProxy#520f7 relayoutBoundary=up23
            parentData: offset=Offset(0.0, 6.0) (can use size)
            constraints: BoxConstraints(w=376.7, 0.0<=h<=Infinity)
            size: Size(376.7, 147.0)
            child: RenderParagraph#9e049 relayoutBoundary=up24
                parentData: <none> (can use size)
                constraints: BoxConstraints(w=376.7, 0.0<=h<=Infinity)
                size: Size(376.7, 147.0)
                textAlign: left
                textDirection: ltr
                softWrap: wrapping at box width
                overflow: clip
                locale: en
                maxLines: unlimited
                text: TextSpan
                    debugLabel: ((englishLike bodyMedium 2021).merge(((blackMountainView bodyMedium).apply).merge((blackMountainView bodyMedium).apply))).copyWith
                    inherit: false
                    color: Color(0xff383330)
                  family: Roboto
                    size: 14.0
                    weight: 400
                    letterSpacing: 0.3
                    baseline: alphabetic
                    height: 1.4x
                    leadingDistribution: even
                    decoration: Color(0xff383330) TextDecoration.none
RenderObject: RenderEditor#baed4 relayoutBoundary=up21
    parentData: <none> (can use size)
    constraints: BoxConstraints(w=392.7, 0.0<=h<=Infinity)
    size: Size(392.7, 163.0)
    child 1: RenderEditableTextLine#ddea0 relayoutBoundary=up22
        parentData: offset=Offset(8.0, 0.0) (can use size)
        constraints: BoxConstraints(w=376.7, 0.0<=h<=Infinity)
        size: Size(376.7, 163.0)
        body: RenderParagraphProxy#520f7 relayoutBoundary=up23
            parentData: offset=Offset(0.0, 6.0) (can use size)
            constraints: BoxConstraints(w=376.7, 0.0<=h<=Infinity)
            size: Size(376.7, 147.0)
            child: RenderParagraph#9e049 relayoutBoundary=up24
                parentData: <none> (can use size)
                constraints: BoxConstraints(w=376.7, 0.0<=h<=Infinity)
                size: Size(376.7, 147.0)
                textAlign: left
                textDirection: ltr
                softWrap: wrapping at box width
                overflow: clip
                locale: en
                maxLines: unlimited
                text: TextSpan
                    debugLabel: ((englishLike bodyMedium 2021).merge(((blackMountainView bodyMedium).apply).merge((blackMountainView bodyMedium).apply))).copyWith
                    inherit: false
                    color: Color(0xff383330)
                    family: Roboto
                    size: 14.0
                  weight: 400
                    letterSpacing: 0.3
                    baseline: alphabetic
                    height: 1.4x
                    leadingDistribution: even
                    decoration: Color(0xff383330) TextDecoration.none
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by scheduler library ═════════════════════════════════
No child at position TextPosition(offset: 300, affinity: TextAffinity.downstream)
'package:fleather/src/rendering/editable_box.dart':
Failed assertion: line 245 pos 12: 'targetChild != null'
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by scheduler library ═════════════════════════════════
No child at position TextPosition(offset: 300, affinity: TextAffinity.downstream)
'package:fleather/src/rendering/editable_box.dart':
Failed assertion: line 245 pos 12: 'targetChild != null'
════════════════════════════════════════════════════════════════════════════════
D/EGL_emulation( 8584): app_time_stats: avg=7270.58ms min=298.02ms max=14243.13ms count=2
I/flutter ( 8584): 300
D/InputMethodManager( 8584): showSoftInput() view=io.flutter.embedding.android.FlutterView{3dc6dc5 VFE...... .F...... 0,0-1080,2214 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 8584): show(ime(), fromIme=true)
D/EGL_emulation( 8584): app_time_stats: avg=22.32ms min=2.87ms max=610.83ms count=38

════════ Exception caught by scheduler library ═════════════════════════════════
No child at position TextPosition(offset: 300, affinity: TextAffinity.downstream)
'package:fleather/src/rendering/editable_box.dart':
Failed assertion: line 245 pos 12: 'targetChild != null'
════════════════════════════════════════════════════════════════════════════════
I/flutter ( 8584): 300
D/InputMethodManager( 8584): showSoftInput() view=io.flutter.embedding.android.FlutterView{3dc6dc5 VFE...... .F...... 0,0-1080,2214 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 8584): show(ime(), fromIme=true)
D/EGL_emulation( 8584): app_time_stats: avg=49.25ms min=12.85ms max=1167.86ms count=38
ember11498 commented 4 months ago

Also, if I want to formatText to background red when user overflows 300 characters per example the formatText itself triggers the listener again and again going on an infinite loop.

I would help you doing the code but I am not the right person as I have got into coding and dart in general only 1 year ago, not experienced enough for the task.