|  | @@ -10,6 +10,143 @@ import 'image.dart';
 | 
	
		
			
			| 10 | 10 |  import 'theme.dart';
 | 
	
		
			
			| 11 | 11 |  import 'toolbar.dart';
 | 
	
		
			
			| 12 | 12 |  
 | 
	
		
			
			|  | 13 | +class ZefyrEditorScope extends ChangeNotifier {
 | 
	
		
			
			|  | 14 | +  ZefyrEditorScope({
 | 
	
		
			
			|  | 15 | +    @required ZefyrImageDelegate imageDelegate,
 | 
	
		
			
			|  | 16 | +    @required ZefyrController controller,
 | 
	
		
			
			|  | 17 | +    @required FocusNode focusNode,
 | 
	
		
			
			|  | 18 | +    @required FocusNode toolbarFocusNode,
 | 
	
		
			
			|  | 19 | +  })  : _controller = controller,
 | 
	
		
			
			|  | 20 | +        _imageDelegate = imageDelegate,
 | 
	
		
			
			|  | 21 | +        _focusNode = focusNode,
 | 
	
		
			
			|  | 22 | +        _toolbarFocusNode = toolbarFocusNode {
 | 
	
		
			
			|  | 23 | +    _selectionStyle = _controller.getSelectionStyle();
 | 
	
		
			
			|  | 24 | +    _selection = _controller.selection;
 | 
	
		
			
			|  | 25 | +    _controller.addListener(_handleControllerChange);
 | 
	
		
			
			|  | 26 | +    toolbarFocusNode.addListener(_handleFocusChange);
 | 
	
		
			
			|  | 27 | +    _focusNode.addListener(_handleFocusChange);
 | 
	
		
			
			|  | 28 | +  }
 | 
	
		
			
			|  | 29 | +
 | 
	
		
			
			|  | 30 | +  bool _disposed = false;
 | 
	
		
			
			|  | 31 | +
 | 
	
		
			
			|  | 32 | +  ZefyrImageDelegate _imageDelegate;
 | 
	
		
			
			|  | 33 | +  ZefyrImageDelegate get imageDelegate => _imageDelegate;
 | 
	
		
			
			|  | 34 | +
 | 
	
		
			
			|  | 35 | +  FocusNode _focusNode;
 | 
	
		
			
			|  | 36 | +  FocusNode _toolbarFocusNode;
 | 
	
		
			
			|  | 37 | +  FocusNode get toolbarFocusNode => _toolbarFocusNode;
 | 
	
		
			
			|  | 38 | +
 | 
	
		
			
			|  | 39 | +  ZefyrController _controller;
 | 
	
		
			
			|  | 40 | +  NotusStyle get selectionStyle => _selectionStyle;
 | 
	
		
			
			|  | 41 | +  NotusStyle _selectionStyle;
 | 
	
		
			
			|  | 42 | +  TextSelection get selection => _selection;
 | 
	
		
			
			|  | 43 | +  TextSelection _selection;
 | 
	
		
			
			|  | 44 | +
 | 
	
		
			
			|  | 45 | +  @override
 | 
	
		
			
			|  | 46 | +  void dispose() {
 | 
	
		
			
			|  | 47 | +    assert(!_disposed);
 | 
	
		
			
			|  | 48 | +    _controller.removeListener(_handleControllerChange);
 | 
	
		
			
			|  | 49 | +    _toolbarFocusNode.removeListener(_handleFocusChange);
 | 
	
		
			
			|  | 50 | +    _focusNode.removeListener(_handleFocusChange);
 | 
	
		
			
			|  | 51 | +    _disposed = true;
 | 
	
		
			
			|  | 52 | +    super.dispose();
 | 
	
		
			
			|  | 53 | +  }
 | 
	
		
			
			|  | 54 | +
 | 
	
		
			
			|  | 55 | +  void _updateControllerIfNeeded(ZefyrController value) {
 | 
	
		
			
			|  | 56 | +    if (_controller != value) {
 | 
	
		
			
			|  | 57 | +      _controller.removeListener(_handleControllerChange);
 | 
	
		
			
			|  | 58 | +      _controller = value;
 | 
	
		
			
			|  | 59 | +      _selectionStyle = _controller.getSelectionStyle();
 | 
	
		
			
			|  | 60 | +      _selection = _controller.selection;
 | 
	
		
			
			|  | 61 | +      _controller.addListener(_handleControllerChange);
 | 
	
		
			
			|  | 62 | +      notifyListeners();
 | 
	
		
			
			|  | 63 | +    }
 | 
	
		
			
			|  | 64 | +  }
 | 
	
		
			
			|  | 65 | +
 | 
	
		
			
			|  | 66 | +  void _updateFocusNodeIfNeeded(FocusNode value) {
 | 
	
		
			
			|  | 67 | +    if (_focusNode != value) {
 | 
	
		
			
			|  | 68 | +      _focusNode.removeListener(_handleFocusChange);
 | 
	
		
			
			|  | 69 | +      _focusNode = value;
 | 
	
		
			
			|  | 70 | +      _focusNode.addListener(_handleFocusChange);
 | 
	
		
			
			|  | 71 | +      notifyListeners();
 | 
	
		
			
			|  | 72 | +    }
 | 
	
		
			
			|  | 73 | +  }
 | 
	
		
			
			|  | 74 | +
 | 
	
		
			
			|  | 75 | +  void _updateImageDelegateIfNeeded(ZefyrImageDelegate value) {
 | 
	
		
			
			|  | 76 | +    if (_imageDelegate != value) {
 | 
	
		
			
			|  | 77 | +      _imageDelegate = value;
 | 
	
		
			
			|  | 78 | +      notifyListeners();
 | 
	
		
			
			|  | 79 | +    }
 | 
	
		
			
			|  | 80 | +  }
 | 
	
		
			
			|  | 81 | +
 | 
	
		
			
			|  | 82 | +  void _handleControllerChange() {
 | 
	
		
			
			|  | 83 | +    assert(!_disposed);
 | 
	
		
			
			|  | 84 | +    final attrs = _controller.getSelectionStyle();
 | 
	
		
			
			|  | 85 | +    final selection = _controller.selection;
 | 
	
		
			
			|  | 86 | +    if (_selectionStyle != attrs || _selection != selection) {
 | 
	
		
			
			|  | 87 | +      _selectionStyle = attrs;
 | 
	
		
			
			|  | 88 | +      _selection = _controller.selection;
 | 
	
		
			
			|  | 89 | +      notifyListeners();
 | 
	
		
			
			|  | 90 | +    }
 | 
	
		
			
			|  | 91 | +  }
 | 
	
		
			
			|  | 92 | +
 | 
	
		
			
			|  | 93 | +  void _handleFocusChange() {
 | 
	
		
			
			|  | 94 | +    assert(!_disposed);
 | 
	
		
			
			|  | 95 | +    if (focusOwner == FocusOwner.none && !_selection.isCollapsed) {
 | 
	
		
			
			|  | 96 | +      // Collapse selection if there is nothing focused.
 | 
	
		
			
			|  | 97 | +      _controller.updateSelection(_selection.copyWith(
 | 
	
		
			
			|  | 98 | +        baseOffset: _selection.extentOffset,
 | 
	
		
			
			|  | 99 | +        extentOffset: _selection.extentOffset,
 | 
	
		
			
			|  | 100 | +      ));
 | 
	
		
			
			|  | 101 | +    }
 | 
	
		
			
			|  | 102 | +    notifyListeners();
 | 
	
		
			
			|  | 103 | +  }
 | 
	
		
			
			|  | 104 | +
 | 
	
		
			
			|  | 105 | +  FocusOwner get focusOwner {
 | 
	
		
			
			|  | 106 | +    assert(!_disposed);
 | 
	
		
			
			|  | 107 | +    if (_focusNode.hasFocus) {
 | 
	
		
			
			|  | 108 | +      return FocusOwner.editor;
 | 
	
		
			
			|  | 109 | +    } else if (toolbarFocusNode.hasFocus) {
 | 
	
		
			
			|  | 110 | +      return FocusOwner.toolbar;
 | 
	
		
			
			|  | 111 | +    } else {
 | 
	
		
			
			|  | 112 | +      return FocusOwner.none;
 | 
	
		
			
			|  | 113 | +    }
 | 
	
		
			
			|  | 114 | +  }
 | 
	
		
			
			|  | 115 | +
 | 
	
		
			
			|  | 116 | +  void updateSelection(TextSelection value,
 | 
	
		
			
			|  | 117 | +      {ChangeSource source: ChangeSource.remote}) {
 | 
	
		
			
			|  | 118 | +    assert(!_disposed);
 | 
	
		
			
			|  | 119 | +    _controller.updateSelection(value, source: source);
 | 
	
		
			
			|  | 120 | +  }
 | 
	
		
			
			|  | 121 | +
 | 
	
		
			
			|  | 122 | +  void formatSelection(NotusAttribute value) {
 | 
	
		
			
			|  | 123 | +    assert(!_disposed);
 | 
	
		
			
			|  | 124 | +    _controller.formatSelection(value);
 | 
	
		
			
			|  | 125 | +  }
 | 
	
		
			
			|  | 126 | +
 | 
	
		
			
			|  | 127 | +  void focus(BuildContext context) {
 | 
	
		
			
			|  | 128 | +    assert(!_disposed);
 | 
	
		
			
			|  | 129 | +    FocusScope.of(context).requestFocus(_focusNode);
 | 
	
		
			
			|  | 130 | +  }
 | 
	
		
			
			|  | 131 | +
 | 
	
		
			
			|  | 132 | +  void hideKeyboard() {
 | 
	
		
			
			|  | 133 | +    assert(!_disposed);
 | 
	
		
			
			|  | 134 | +    _focusNode.unfocus();
 | 
	
		
			
			|  | 135 | +  }
 | 
	
		
			
			|  | 136 | +}
 | 
	
		
			
			|  | 137 | +
 | 
	
		
			
			|  | 138 | +class _ZefyrEditorScope extends InheritedWidget {
 | 
	
		
			
			|  | 139 | +  final ZefyrEditorScope scope;
 | 
	
		
			
			|  | 140 | +
 | 
	
		
			
			|  | 141 | +  _ZefyrEditorScope({Key key, Widget child, @required this.scope})
 | 
	
		
			
			|  | 142 | +      : super(key: key, child: child);
 | 
	
		
			
			|  | 143 | +
 | 
	
		
			
			|  | 144 | +  @override
 | 
	
		
			
			|  | 145 | +  bool updateShouldNotify(_ZefyrEditorScope oldWidget) {
 | 
	
		
			
			|  | 146 | +    return oldWidget.scope != scope;
 | 
	
		
			
			|  | 147 | +  }
 | 
	
		
			
			|  | 148 | +}
 | 
	
		
			
			|  | 149 | +
 | 
	
		
			
			| 13 | 150 |  /// Widget for editing Zefyr documents.
 | 
	
		
			
			| 14 | 151 |  class ZefyrEditor extends StatefulWidget {
 | 
	
		
			
			| 15 | 152 |    const ZefyrEditor({
 | 
	
	
		
			
			|  | @@ -34,119 +171,46 @@ class ZefyrEditor extends StatefulWidget {
 | 
	
		
			
			| 34 | 171 |    final EdgeInsets padding;
 | 
	
		
			
			| 35 | 172 |  
 | 
	
		
			
			| 36 | 173 |    static ZefyrEditorScope of(BuildContext context) {
 | 
	
		
			
			| 37 |  | -    ZefyrEditorScope scope =
 | 
	
		
			
			| 38 |  | -        context.inheritFromWidgetOfExactType(ZefyrEditorScope);
 | 
	
		
			
			| 39 |  | -    return scope;
 | 
	
		
			
			|  | 174 | +    _ZefyrEditorScope widget =
 | 
	
		
			
			|  | 175 | +        context.inheritFromWidgetOfExactType(_ZefyrEditorScope);
 | 
	
		
			
			|  | 176 | +    return widget.scope;
 | 
	
		
			
			| 40 | 177 |    }
 | 
	
		
			
			| 41 | 178 |  
 | 
	
		
			
			| 42 | 179 |    @override
 | 
	
		
			
			| 43 | 180 |    _ZefyrEditorState createState() => new _ZefyrEditorState();
 | 
	
		
			
			| 44 | 181 |  }
 | 
	
		
			
			| 45 | 182 |  
 | 
	
		
			
			| 46 |  | -/// Inherited widget which provides access to shared state of a Zefyr editor.
 | 
	
		
			
			| 47 |  | -class ZefyrEditorScope extends InheritedWidget {
 | 
	
		
			
			| 48 |  | -  /// Current selection style
 | 
	
		
			
			| 49 |  | -  final NotusStyle selectionStyle;
 | 
	
		
			
			| 50 |  | -  final TextSelection selection;
 | 
	
		
			
			| 51 |  | -  final FocusOwner focusOwner;
 | 
	
		
			
			| 52 |  | -  final FocusNode toolbarFocusNode;
 | 
	
		
			
			| 53 |  | -  final ZefyrImageDelegate imageDelegate;
 | 
	
		
			
			| 54 |  | -  final ZefyrController _controller;
 | 
	
		
			
			| 55 |  | -  final FocusNode _focusNode;
 | 
	
		
			
			| 56 |  | -
 | 
	
		
			
			| 57 |  | -  ZefyrEditorScope({
 | 
	
		
			
			| 58 |  | -    Key key,
 | 
	
		
			
			| 59 |  | -    @required Widget child,
 | 
	
		
			
			| 60 |  | -    @required this.selectionStyle,
 | 
	
		
			
			| 61 |  | -    @required this.selection,
 | 
	
		
			
			| 62 |  | -    @required this.focusOwner,
 | 
	
		
			
			| 63 |  | -    @required this.toolbarFocusNode,
 | 
	
		
			
			| 64 |  | -    @required this.imageDelegate,
 | 
	
		
			
			| 65 |  | -    @required ZefyrController controller,
 | 
	
		
			
			| 66 |  | -    @required FocusNode focusNode,
 | 
	
		
			
			| 67 |  | -  })  : _controller = controller,
 | 
	
		
			
			| 68 |  | -        _focusNode = focusNode,
 | 
	
		
			
			| 69 |  | -        super(key: key, child: child);
 | 
	
		
			
			| 70 |  | -
 | 
	
		
			
			| 71 |  | -  void updateSelection(TextSelection value,
 | 
	
		
			
			| 72 |  | -      {ChangeSource source: ChangeSource.remote}) {
 | 
	
		
			
			| 73 |  | -    _controller.updateSelection(value, source: source);
 | 
	
		
			
			| 74 |  | -  }
 | 
	
		
			
			| 75 |  | -
 | 
	
		
			
			| 76 |  | -  void formatSelection(NotusAttribute value) {
 | 
	
		
			
			| 77 |  | -    _controller.formatSelection(value);
 | 
	
		
			
			| 78 |  | -  }
 | 
	
		
			
			| 79 |  | -
 | 
	
		
			
			| 80 |  | -  void focus(BuildContext context) {
 | 
	
		
			
			| 81 |  | -    FocusScope.of(context).requestFocus(_focusNode);
 | 
	
		
			
			| 82 |  | -  }
 | 
	
		
			
			| 83 |  | -
 | 
	
		
			
			| 84 |  | -  void hideKeyboard() {
 | 
	
		
			
			| 85 |  | -    _focusNode.unfocus();
 | 
	
		
			
			| 86 |  | -  }
 | 
	
		
			
			| 87 |  | -
 | 
	
		
			
			| 88 |  | -  @override
 | 
	
		
			
			| 89 |  | -  bool updateShouldNotify(ZefyrEditorScope oldWidget) {
 | 
	
		
			
			| 90 |  | -    return (selectionStyle != oldWidget.selectionStyle ||
 | 
	
		
			
			| 91 |  | -        selection != oldWidget.selection ||
 | 
	
		
			
			| 92 |  | -        focusOwner != oldWidget.focusOwner ||
 | 
	
		
			
			| 93 |  | -        imageDelegate != oldWidget.imageDelegate);
 | 
	
		
			
			| 94 |  | -  }
 | 
	
		
			
			| 95 |  | -}
 | 
	
		
			
			| 96 |  | -
 | 
	
		
			
			| 97 | 183 |  class _ZefyrEditorState extends State<ZefyrEditor> {
 | 
	
		
			
			| 98 | 184 |    final FocusNode _toolbarFocusNode = new FocusNode();
 | 
	
		
			
			| 99 |  | -
 | 
	
		
			
			| 100 |  | -  NotusStyle _selectionStyle;
 | 
	
		
			
			| 101 |  | -  TextSelection _selection;
 | 
	
		
			
			| 102 |  | -  FocusOwner _focusOwner;
 | 
	
		
			
			| 103 | 185 |    ZefyrImageDelegate _imageDelegate;
 | 
	
		
			
			| 104 |  | -
 | 
	
		
			
			| 105 |  | -  FocusOwner getFocusOwner() {
 | 
	
		
			
			| 106 |  | -    if (widget.focusNode.hasFocus) {
 | 
	
		
			
			| 107 |  | -      return FocusOwner.editor;
 | 
	
		
			
			| 108 |  | -    } else if (_toolbarFocusNode.hasFocus) {
 | 
	
		
			
			| 109 |  | -      return FocusOwner.toolbar;
 | 
	
		
			
			| 110 |  | -    } else {
 | 
	
		
			
			| 111 |  | -      return FocusOwner.none;
 | 
	
		
			
			| 112 |  | -    }
 | 
	
		
			
			| 113 |  | -  }
 | 
	
		
			
			|  | 186 | +  ZefyrEditorScope _scope;
 | 
	
		
			
			| 114 | 187 |  
 | 
	
		
			
			| 115 | 188 |    @override
 | 
	
		
			
			| 116 | 189 |    void initState() {
 | 
	
		
			
			| 117 | 190 |      super.initState();
 | 
	
		
			
			| 118 |  | -    _selectionStyle = widget.controller.getSelectionStyle();
 | 
	
		
			
			| 119 |  | -    _selection = widget.controller.selection;
 | 
	
		
			
			| 120 |  | -    _focusOwner = getFocusOwner();
 | 
	
		
			
			| 121 | 191 |      _imageDelegate = widget.imageDelegate ?? new ZefyrDefaultImageDelegate();
 | 
	
		
			
			| 122 |  | -    widget.controller.addListener(_handleControllerChange);
 | 
	
		
			
			| 123 |  | -    _toolbarFocusNode.addListener(_handleFocusChange);
 | 
	
		
			
			| 124 |  | -    widget.focusNode.addListener(_handleFocusChange);
 | 
	
		
			
			|  | 192 | +    _scope = ZefyrEditorScope(
 | 
	
		
			
			|  | 193 | +      toolbarFocusNode: _toolbarFocusNode,
 | 
	
		
			
			|  | 194 | +      imageDelegate: _imageDelegate,
 | 
	
		
			
			|  | 195 | +      controller: widget.controller,
 | 
	
		
			
			|  | 196 | +      focusNode: widget.focusNode,
 | 
	
		
			
			|  | 197 | +    );
 | 
	
		
			
			| 125 | 198 |    }
 | 
	
		
			
			| 126 | 199 |  
 | 
	
		
			
			| 127 | 200 |    @override
 | 
	
		
			
			| 128 | 201 |    void didUpdateWidget(ZefyrEditor oldWidget) {
 | 
	
		
			
			| 129 | 202 |      super.didUpdateWidget(oldWidget);
 | 
	
		
			
			| 130 |  | -    if (widget.focusNode != oldWidget.focusNode) {
 | 
	
		
			
			| 131 |  | -      oldWidget.focusNode.removeListener(_handleFocusChange);
 | 
	
		
			
			| 132 |  | -      widget.focusNode.addListener(_handleFocusChange);
 | 
	
		
			
			| 133 |  | -    }
 | 
	
		
			
			| 134 |  | -    if (widget.controller != oldWidget.controller) {
 | 
	
		
			
			| 135 |  | -      oldWidget.controller.removeListener(_handleControllerChange);
 | 
	
		
			
			| 136 |  | -      widget.controller.addListener(_handleControllerChange);
 | 
	
		
			
			| 137 |  | -      _selectionStyle = widget.controller.getSelectionStyle();
 | 
	
		
			
			| 138 |  | -      _selection = widget.controller.selection;
 | 
	
		
			
			| 139 |  | -    }
 | 
	
		
			
			|  | 203 | +    _scope._updateControllerIfNeeded(widget.controller);
 | 
	
		
			
			|  | 204 | +    _scope._updateFocusNodeIfNeeded(widget.focusNode);
 | 
	
		
			
			| 140 | 205 |      if (widget.imageDelegate != oldWidget.imageDelegate) {
 | 
	
		
			
			| 141 | 206 |        _imageDelegate = widget.imageDelegate ?? new ZefyrDefaultImageDelegate();
 | 
	
		
			
			|  | 207 | +      _scope._updateImageDelegateIfNeeded(_imageDelegate);
 | 
	
		
			
			| 142 | 208 |      }
 | 
	
		
			
			| 143 | 209 |    }
 | 
	
		
			
			| 144 | 210 |  
 | 
	
		
			
			| 145 | 211 |    @override
 | 
	
		
			
			| 146 | 212 |    void dispose() {
 | 
	
		
			
			| 147 |  | -    widget.controller.removeListener(_handleControllerChange);
 | 
	
		
			
			| 148 |  | -    widget.focusNode.removeListener(_handleFocusChange);
 | 
	
		
			
			| 149 |  | -    _toolbarFocusNode.removeListener(_handleFocusChange);
 | 
	
		
			
			|  | 213 | +    _scope.dispose();
 | 
	
		
			
			| 150 | 214 |      _toolbarFocusNode.dispose();
 | 
	
		
			
			| 151 | 215 |      super.dispose();
 | 
	
		
			
			| 152 | 216 |    }
 | 
	
	
		
			
			|  | @@ -165,8 +229,8 @@ class _ZefyrEditorState extends State<ZefyrEditor> {
 | 
	
		
			
			| 165 | 229 |      final children = <Widget>[];
 | 
	
		
			
			| 166 | 230 |      children.add(Expanded(child: editable));
 | 
	
		
			
			| 167 | 231 |      final toolbar = ZefyrToolbar(
 | 
	
		
			
			|  | 232 | +      editor: _scope,
 | 
	
		
			
			| 168 | 233 |        focusNode: _toolbarFocusNode,
 | 
	
		
			
			| 169 |  | -      controller: widget.controller,
 | 
	
		
			
			| 170 | 234 |        delegate: widget.toolbarDelegate,
 | 
	
		
			
			| 171 | 235 |      );
 | 
	
		
			
			| 172 | 236 |      children.add(toolbar);
 | 
	
	
		
			
			|  | @@ -179,40 +243,10 @@ class _ZefyrEditorState extends State<ZefyrEditor> {
 | 
	
		
			
			| 179 | 243 |  
 | 
	
		
			
			| 180 | 244 |      return ZefyrTheme(
 | 
	
		
			
			| 181 | 245 |        data: actualTheme,
 | 
	
		
			
			| 182 |  | -      child: ZefyrEditorScope(
 | 
	
		
			
			| 183 |  | -        selection: _selection,
 | 
	
		
			
			| 184 |  | -        selectionStyle: _selectionStyle,
 | 
	
		
			
			| 185 |  | -        focusOwner: _focusOwner,
 | 
	
		
			
			| 186 |  | -        toolbarFocusNode: _toolbarFocusNode,
 | 
	
		
			
			| 187 |  | -        imageDelegate: _imageDelegate,
 | 
	
		
			
			| 188 |  | -        controller: widget.controller,
 | 
	
		
			
			| 189 |  | -        focusNode: widget.focusNode,
 | 
	
		
			
			|  | 246 | +      child: _ZefyrEditorScope(
 | 
	
		
			
			|  | 247 | +        scope: _scope,
 | 
	
		
			
			| 190 | 248 |          child: Column(children: children),
 | 
	
		
			
			| 191 | 249 |        ),
 | 
	
		
			
			| 192 | 250 |      );
 | 
	
		
			
			| 193 | 251 |    }
 | 
	
		
			
			| 194 |  | -
 | 
	
		
			
			| 195 |  | -  void _handleControllerChange() {
 | 
	
		
			
			| 196 |  | -    final attrs = widget.controller.getSelectionStyle();
 | 
	
		
			
			| 197 |  | -    final selection = widget.controller.selection;
 | 
	
		
			
			| 198 |  | -    if (_selectionStyle != attrs || _selection != selection) {
 | 
	
		
			
			| 199 |  | -      setState(() {
 | 
	
		
			
			| 200 |  | -        _selectionStyle = attrs;
 | 
	
		
			
			| 201 |  | -        _selection = widget.controller.selection;
 | 
	
		
			
			| 202 |  | -      });
 | 
	
		
			
			| 203 |  | -    }
 | 
	
		
			
			| 204 |  | -  }
 | 
	
		
			
			| 205 |  | -
 | 
	
		
			
			| 206 |  | -  void _handleFocusChange() {
 | 
	
		
			
			| 207 |  | -    setState(() {
 | 
	
		
			
			| 208 |  | -      _focusOwner = getFocusOwner();
 | 
	
		
			
			| 209 |  | -      if (_focusOwner == FocusOwner.none && !_selection.isCollapsed) {
 | 
	
		
			
			| 210 |  | -        // Collapse selection if there is nothing focused.
 | 
	
		
			
			| 211 |  | -        widget.controller.updateSelection(_selection.copyWith(
 | 
	
		
			
			| 212 |  | -          baseOffset: _selection.extentOffset,
 | 
	
		
			
			| 213 |  | -          extentOffset: _selection.extentOffset,
 | 
	
		
			
			| 214 |  | -        ));
 | 
	
		
			
			| 215 |  | -      }
 | 
	
		
			
			| 216 |  | -    });
 | 
	
		
			
			| 217 |  | -  }
 | 
	
		
			
			| 218 | 252 |  }
 |