Explorar el Código

add link GestureRecognizer

lucky1213 hace 4 años
padre
commit
a4712443e6

+ 2
- 22
packages/zefyr/example/lib/src/full_page.dart Ver fichero

@@ -83,24 +83,7 @@ class _FullPageEditorScreenState extends State<FullPageEditorScreen> {
83 83
           )
84 84
         ],
85 85
       ),
86
-      body: Column(
87
-        children: <Widget>[
88
-          Container(
89
-            child: RichText(
90
-                text: TextSpan(children: [
91
-              TextSpan(text: 'Flutter is', style: TextStyle(color: Colors.black)),
92
-              WidgetSpan(
93
-                child: SizedBox(
94
-                  height: 20,
95
-                  width: 20,
96
-                    child: Image.network(
97
-                        'http://links-emoticons.oss-cn-hangzhou.aliyuncs.com/v3/e100@2x.gif'),),
98
-              ),
99
-              TextSpan(text: '123123', style: TextStyle(color: Colors.black)),
100
-            ])),
101
-          ),
102
-          Expanded(
103
-            child: ZefyrScaffold(
86
+      body: ZefyrScaffold(
104 87
               child: ZefyrTheme(
105 88
                 data: ZefyrThemeData(
106 89
                   // attributeTheme: AttributeTheme(
@@ -113,16 +96,13 @@ class _FullPageEditorScreenState extends State<FullPageEditorScreen> {
113 96
                   autofocus: false,
114 97
                   controller: _controller,
115 98
                   focusNode: _focusNode,
116
-                  mode: ZefyrMode.edit,
99
+                  mode: ZefyrMode.select,
117 100
                   imageDelegate: CustomImageDelegate(),
118 101
                   linkDelegate: CustomLinkDelegate(),
119 102
                   keyboardAppearance: _darkTheme ? Brightness.dark : Brightness.light,
120 103
                 ),
121 104
               ),
122 105
             ),
123
-          ),
124
-        ],
125
-      ),
126 106
     );
127 107
     if (_darkTheme) {
128 108
       return Theme(data: ThemeData.dark(), child: result);

+ 9
- 2
packages/zefyr/example/lib/src/images.dart Ver fichero

@@ -4,6 +4,8 @@
4 4
 
5 5
 import 'dart:io';
6 6
 import 'dart:typed_data';
7
+import 'package:flutter/gestures.dart';
8
+import 'package:flutter/services.dart';
7 9
 import 'package:image/image.dart' as Im;
8 10
 
9 11
 import 'package:flutter/material.dart';
@@ -77,11 +79,11 @@ class CustomLinkDelegate implements ZefyrLinkDelegate {
77 79
                 color: Colors.white,
78 80
                 child: Column(
79 81
                   children: <Widget>[
80
-                    TextField(controller: _controller,),
82
+                    TextField(controller: _controller, inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],),
81 83
                     FlatButton(
82 84
                       onPressed: () {
83 85
                         Navigator.pop(buildContext, ZefyrLinkEntity(
84
-                          text: '测试用',
86
+                          text: '测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用测试用',
85 87
                           url: _controller.text,
86 88
                         ));
87 89
                       },
@@ -103,6 +105,11 @@ class CustomLinkDelegate implements ZefyrLinkDelegate {
103 105
     );
104 106
   }
105 107
   
108
+  @override
109
+  GestureRecognizer provideLinkGesture(ZefyrLinkEntity value) {
110
+    // return 
111
+    return TapGestureRecognizer()..onTap = () {print('The word touched is 123123');};
112
+  }
106 113
 }
107 114
 
108 115
 Widget _buildMaterialDialogTransitions(

+ 14
- 170
packages/zefyr/lib/src/widgets/buttons.dart Ver fichero

@@ -866,7 +866,7 @@ class _LinkButtonState extends State<LinkButton> {
866 866
 
867 867
   bool hasLink(NotusStyle style) => style.contains(NotusAttribute.link);
868 868
 
869
-  String getLink([String defaultValue]) {
869
+  String getLink([String defaultValue = '']) {
870 870
     final editor = ZefyrToolbar.of(context).editor;
871 871
     final attrs = editor.selectionStyle;
872 872
     if (hasLink(attrs)) {
@@ -875,26 +875,25 @@ class _LinkButtonState extends State<LinkButton> {
875 875
     return defaultValue;
876 876
   }
877 877
 
878
+  String getText([String defaultValue = '']) {
879
+    final editor = ZefyrToolbar.of(context).editor;
880
+    final plainTextEditingValue = editor.controller.plainTextEditingValue;
881
+    if (!editor.selection.isCollapsed) {
882
+      return plainTextEditingValue.text.substring(editor.selection.start, editor.selection.end);
883
+    }
884
+    return defaultValue;
885
+  }
886
+
878 887
   OverlayEntry _overlayEntry;
879 888
 
880 889
   Future<void> showOverlay() async {
881 890
     final editor = ZefyrToolbar.of(context).editor;
882 891
     editor.closeKeyboard(true);
883 892
     var _selection = editor.selection;
884
-    var value = ZefyrLinkEntity();
885
-    if (hasLink(editor.selectionStyle)) {
886
-      value =
887
-          value.copyWith(url: editor.selectionStyle.value(NotusAttribute.link));
888
-    }
889
-    // 已选中
890
-    if (!editor.selection.isCollapsed) {
891
-      var text = editor.controller.document
892
-          .toPlainText()
893
-          .substring(editor.selection.start, editor.selection.end);
894
-      value = value.copyWith(text: text);
895
-    }
896
-    ;
897
-    var result = await editor.linkDelegate.fillLink(context, value);
893
+    var result = await editor.linkDelegate.fillLink(context, ZefyrLinkEntity(
894
+      text: getText(),
895
+      url: getLink(),
896
+    ));
898 897
 
899 898
     if (result != null) {
900 899
       // toolbar.editor.updateSelection(_selection, source: ChangeSource.local);
@@ -997,160 +996,5 @@ class _LinkButtonState extends State<LinkButton> {
997 996
       toolbar.markNeedsRebuild();
998 997
     });
999 998
   }
1000
-
1001
-  Widget buildOverlay(BuildContext context) {
1002
-    final toolbar = ZefyrToolbar.of(context);
1003
-    final style = toolbar.editor.selectionStyle;
1004
-
1005
-    String value = 'Tap to edit link';
1006
-    if (style.contains(NotusAttribute.link)) {
1007
-      value = style.value(NotusAttribute.link);
1008
-    }
1009
-    final clipboardEnabled = value != 'Tap to edit link';
1010
-    final body = !isEditing
1011
-        ? _LinkView(value: value, onTap: edit)
1012
-        : _LinkInput(
1013
-            key: _inputKey,
1014
-            controller: _inputController,
1015
-            formatError: _formatError,
1016
-          );
1017
-    final items = <Widget>[Expanded(child: body)];
1018
-    if (!isEditing) {
1019
-      final unlinkHandler = hasLink(style) ? unlink : null;
1020
-      final copyHandler = clipboardEnabled ? copyToClipboard : null;
1021
-      final openHandler = hasLink(style) ? openInBrowser : null;
1022
-      final buttons = <Widget>[
1023
-        toolbar.buildButton(context, ZefyrToolbarAction.unlink,
1024
-            onPressed: unlinkHandler),
1025
-        toolbar.buildButton(context, ZefyrToolbarAction.clipboardCopy,
1026
-            onPressed: copyHandler),
1027
-        toolbar.buildButton(
1028
-          context,
1029
-          ZefyrToolbarAction.openInBrowser,
1030
-          onPressed: openHandler,
1031
-        ),
1032
-      ];
1033
-      items.addAll(buttons);
1034
-    }
1035
-    final trailingPressed = isEditing ? doneEdit : closeOverlay;
1036
-    final trailingAction =
1037
-        isEditing ? ZefyrToolbarAction.confirm : ZefyrToolbarAction.close;
1038
-
1039
-    return ZefyrToolbarScaffold(
1040
-      body: Row(children: items),
1041
-      trailing: toolbar.buildButton(
1042
-        context,
1043
-        trailingAction,
1044
-        onPressed: trailingPressed,
1045
-      ),
1046
-    );
1047
-  }
1048 999
 }
1049 1000
 
1050
-class _LinkInput extends StatefulWidget {
1051
-  final TextEditingController controller;
1052
-  final bool formatError;
1053
-
1054
-  const _LinkInput(
1055
-      {Key key, @required this.controller, this.formatError = false})
1056
-      : super(key: key);
1057
-
1058
-  @override
1059
-  _LinkInputState createState() {
1060
-    return _LinkInputState();
1061
-  }
1062
-}
1063
-
1064
-class _LinkInputState extends State<_LinkInput> {
1065
-  final FocusNode _focusNode = FocusNode();
1066
-
1067
-  ZefyrScope _editor;
1068
-  bool _didAutoFocus = false;
1069
-
1070
-  @override
1071
-  void didChangeDependencies() {
1072
-    super.didChangeDependencies();
1073
-    if (!_didAutoFocus) {
1074
-      FocusScope.of(context).requestFocus(_focusNode);
1075
-      _didAutoFocus = true;
1076
-    }
1077
-
1078
-    final toolbar = ZefyrToolbar.of(context);
1079
-
1080
-    if (_editor != toolbar.editor) {
1081
-      _editor?.toolbarFocusNode = null;
1082
-      _editor = toolbar.editor;
1083
-      _editor.toolbarFocusNode = _focusNode;
1084
-    }
1085
-  }
1086
-
1087
-  @override
1088
-  void dispose() {
1089
-    _editor?.toolbarFocusNode = null;
1090
-    _focusNode.dispose();
1091
-    _editor = null;
1092
-    super.dispose();
1093
-  }
1094
-
1095
-  @override
1096
-  Widget build(BuildContext context) {
1097
-    final theme = Theme.of(context);
1098
-    final toolbarTheme = ZefyrTheme.of(context).toolbarTheme;
1099
-    final color =
1100
-        widget.formatError ? Colors.redAccent : toolbarTheme.iconColor;
1101
-    final style = theme.textTheme.subhead.copyWith(color: color);
1102
-    return TextField(
1103
-      style: style,
1104
-      keyboardType: TextInputType.url,
1105
-      focusNode: _focusNode,
1106
-      controller: widget.controller,
1107
-      autofocus: true,
1108
-      decoration: InputDecoration(
1109
-        hintText: 'https://',
1110
-        filled: true,
1111
-        fillColor: toolbarTheme.color,
1112
-        border: InputBorder.none,
1113
-        contentPadding: const EdgeInsets.all(10.0),
1114
-      ),
1115
-    );
1116
-  }
1117
-}
1118
-
1119
-class _LinkView extends StatelessWidget {
1120
-  const _LinkView({Key key, @required this.value, this.onTap})
1121
-      : super(key: key);
1122
-  final String value;
1123
-  final VoidCallback onTap;
1124
-
1125
-  @override
1126
-  Widget build(BuildContext context) {
1127
-    final theme = Theme.of(context);
1128
-    final toolbarTheme = ZefyrTheme.of(context).toolbarTheme;
1129
-    Widget widget = ClipRect(
1130
-      child: ListView(
1131
-        scrollDirection: Axis.horizontal,
1132
-        children: <Widget>[
1133
-          Container(
1134
-            alignment: AlignmentDirectional.centerStart,
1135
-            constraints: BoxConstraints(minHeight: ZefyrToolbar.kToolbarHeight),
1136
-            padding: const EdgeInsets.all(10.0),
1137
-            child: Text(
1138
-              value,
1139
-              maxLines: 1,
1140
-              overflow: TextOverflow.ellipsis,
1141
-              style: theme.textTheme.subhead
1142
-                  .copyWith(color: toolbarTheme.disabledIconColor),
1143
-            ),
1144
-          )
1145
-        ],
1146
-      ),
1147
-    );
1148
-    if (onTap != null) {
1149
-      widget = GestureDetector(
1150
-        child: widget,
1151
-        onTap: onTap,
1152
-      );
1153
-    }
1154
-    return widget;
1155
-  }
1156
-}

+ 23
- 6
packages/zefyr/lib/src/widgets/common.dart Ver fichero

@@ -2,6 +2,7 @@
2 2
 // for details. All rights reserved. Use of this source code is governed by a
3 3
 // BSD-style license that can be found in the LICENSE file.
4 4
 import 'package:flutter/cupertino.dart';
5
+import 'package:flutter/gestures.dart';
5 6
 import 'package:flutter/material.dart';
6 7
 import 'package:flutter/rendering.dart';
7 8
 import 'package:flutter/widgets.dart';
@@ -10,6 +11,7 @@ import 'package:notus/notus.dart';
10 11
 import 'editable_box.dart';
11 12
 import 'horizontal_rule.dart';
12 13
 import 'image.dart';
14
+import 'link.dart';
13 15
 import 'rich_text.dart';
14 16
 import 'scope.dart';
15 17
 import 'theme.dart';
@@ -54,6 +56,11 @@ class _ZefyrLineState extends State<ZefyrLine> {
54 56
         node: widget.node,
55 57
         text: buildText(context),
56 58
       );
59
+      // content = RichText(
60
+      //   text: TextSpan(
61
+      //     text: '123',
62
+      //   )
63
+      // );
57 64
     }
58 65
 
59 66
     if (scope.isEditable) {
@@ -119,18 +126,30 @@ class _ZefyrLineState extends State<ZefyrLine> {
119 126
 
120 127
   TextSpan buildText(BuildContext context) {
121 128
     final theme = ZefyrTheme.of(context);
122
-    final List<TextSpan> children = widget.node.children
129
+    final children = widget.node.children
123 130
         .map((node) => _segmentToTextSpan(node, theme))
124 131
         .toList(growable: false);
125 132
     return TextSpan(style: widget.style, children: children);
126 133
   }
127 134
 
128
-  TextSpan _segmentToTextSpan(Node node, ZefyrThemeData theme) {
135
+  InlineSpan _segmentToTextSpan(Node node, ZefyrThemeData theme) {
136
+    final _linkDelegate = ZefyrScope.of(context).linkDelegate;
129 137
     final TextNode segment = node;
130 138
     final attrs = segment.style;
131
-
139
+    GestureRecognizer recognizer = TapGestureRecognizer();
140
+    if (attrs.contains(NotusAttribute.link)) {
141
+      if (_linkDelegate != null) {
142
+        recognizer = ZefyrScope.of(context).linkDelegate.provideLinkGesture(ZefyrLinkEntity(
143
+          text: segment.value,
144
+          url: attrs.value(NotusAttribute.link),
145
+        ));
146
+      }
147
+    }
132 148
     return TextSpan(
133 149
       text: segment.value,
150
+      recognizer: TapGestureRecognizer()..onTap = () {
151
+        print('object');
152
+      },
134 153
       style: _getTextStyle(attrs, theme),
135 154
     );
136 155
   }
@@ -155,9 +174,7 @@ class _ZefyrLineState extends State<ZefyrLine> {
155 174
       result = result.merge(theme.attributeTheme.link);
156 175
     }
157 176
     if (style.contains(NotusAttribute.highlight)) {
158
-      result = result.merge(TextStyle(
159
-        backgroundColor: Color(0xFFFFAF64).withOpacity(0.5),
160
-      ));
177
+      result = result.merge(theme.attributeTheme.highlight);
161 178
     }
162 179
     if (style.contains(NotusAttribute.color)) {
163 180
       final hexStringToColor = (String hex) {

+ 3
- 0
packages/zefyr/lib/src/widgets/link.dart Ver fichero

@@ -1,3 +1,4 @@
1
+import 'package:flutter/gestures.dart';
1 2
 import 'package:flutter/material.dart';
2 3
 import 'package:meta/meta.dart';
3 4
 
@@ -24,4 +25,6 @@ class ZefyrLinkEntity {
24 25
 abstract class ZefyrLinkDelegate {
25 26
 
26 27
   Future<ZefyrLinkEntity> fillLink(BuildContext context, ZefyrLinkEntity value);
28
+
29
+  GestureRecognizer provideLinkGesture(ZefyrLinkEntity value);
27 30
 }

+ 12
- 0
packages/zefyr/lib/src/widgets/theme.dart Ver fichero

@@ -295,6 +295,9 @@ class AttributeTheme {
295 295
   /// Style used to render "italic" text.
296 296
   final TextStyle italic;
297 297
 
298
+  /// Style used to render "highlight" text.
299
+  final TextStyle highlight;
300
+
298 301
   /// Style used to render text containing links.
299 302
   final TextStyle link;
300 303
 
@@ -334,6 +337,7 @@ class AttributeTheme {
334 337
     this.underline,
335 338
     this.deleteline,
336 339
     this.italic,
340
+    this.highlight,
337 341
     this.link,
338 342
     this.heading1,
339 343
     this.heading2,
@@ -374,6 +378,9 @@ class AttributeTheme {
374 378
         decoration: TextDecoration.underline,
375 379
         color: theme.accentColor,
376 380
       ),
381
+      highlight: TextStyle(
382
+        backgroundColor: Color(0xFFFFAF64).withOpacity(0.5),
383
+      ),
377 384
       heading1: LineTheme(
378 385
         textStyle: defaultLineTheme.textStyle.copyWith(
379 386
           fontSize: 24.0,
@@ -463,6 +470,7 @@ class AttributeTheme {
463 470
     TextStyle bold,
464 471
     TextStyle underline,
465 472
     TextStyle deleteline,
473
+    TextStyle highlight,
466 474
     TextStyle italic,
467 475
     TextStyle link,
468 476
     LineTheme heading1,
@@ -480,6 +488,7 @@ class AttributeTheme {
480 488
       bold: bold ?? this.bold,
481 489
       underline: underline ?? this.underline,
482 490
       deleteline: deleteline ?? this.deleteline,
491
+      highlight: highlight ?? this.highlight,
483 492
       italic: italic ?? this.italic,
484 493
       link: link ?? this.link,
485 494
       heading1: heading1 ?? this.heading1,
@@ -503,6 +512,7 @@ class AttributeTheme {
503 512
       bold: bold?.merge(other.bold) ?? other.bold,
504 513
       underline: underline?.merge(other.underline) ?? other.underline,
505 514
       deleteline: underline?.merge(other.deleteline) ?? other.deleteline,
515
+      highlight: highlight?.merge(other.highlight) ?? other.highlight,
506 516
       italic: italic?.merge(other.italic) ?? other.italic,
507 517
       link: link?.merge(other.link) ?? other.link,
508 518
       heading1: heading1?.merge(other.heading1) ?? other.heading1,
@@ -525,6 +535,7 @@ class AttributeTheme {
525 535
     return (otherTheme.bold == bold) &&
526 536
         (otherTheme.underline == underline) &&
527 537
         (otherTheme.deleteline == deleteline) &&
538
+        (otherTheme.highlight == highlight) &&
528 539
         (otherTheme.italic == italic) &&
529 540
         (otherTheme.link == link) &&
530 541
         (otherTheme.heading1 == heading1) &&
@@ -545,6 +556,7 @@ class AttributeTheme {
545 556
       bold,
546 557
       underline,
547 558
       deleteline,
559
+      highlight,
548 560
       italic,
549 561
       link,
550 562
       heading1,