@@ -5,6 +5,11 @@ import 'package:flutter/material.dart';
55import 'package:flutter/services.dart' ;
66import 'package:hugeicons/hugeicons.dart' ;
77
8+ /// 统一的 marker 字符:
9+ /// - encodedString 中用于标记 mention 结束(@label + marker)
10+ /// - driverString 中用于 TextField 驱动的 placeholder(mention 视为一个字符)
11+ const String _marker = '\u E000' ;
12+
813sealed class Segment {
914 int get driverLength => switch (this ) {
1015 TextSegment (: final value) => value.length,
@@ -42,11 +47,6 @@ typedef MentionItemBuilder = Widget Function(
4247 String query,
4348);
4449
45- /// 统一的 marker 字符:
46- /// - encodedString 中用于标记 mention 结束(@label + marker)
47- /// - driverString 中用于 TextField 驱动的 placeholder(mention 视为一个字符)
48- const String _marker = '\u E000' ;
49-
5050class MentionSegmentSerializer {
5151 static String encode (List <Segment > segments) {
5252 return segments
@@ -117,14 +117,19 @@ class MentionTextController extends TextEditingController {
117117 MentionTextController ({String ? text})
118118 : _segments = text != null ? MentionSegmentSerializer .decode (text) : < Segment > [],
119119 super (text: '' ) {
120- final initialDriver = _segmentsToDriverString (_segments );
120+ final initialDriver = _segmentsToDriverString ();
121121 super .value = TextEditingValue (
122122 text: initialDriver,
123123 selection: TextSelection .collapsed (offset: initialDriver.length),
124124 );
125125 _updateMentionState ();
126126 }
127127
128+ /// 将 segment 转化成 value 给 TextEditingController 使用
129+ String _segmentsToDriverString () {
130+ return _segments.map ((s) => s.toDriverString (_marker)).join ();
131+ }
132+
128133 List <Segment > get segments => List .unmodifiable (_segments);
129134
130135 String get displayText => MentionSegmentSerializer .encode (_segments);
@@ -150,7 +155,7 @@ class MentionTextController extends TextEditingController {
150155 if (index < 0 ) return false ;
151156
152157 _segments.removeAt (index);
153- final driver = _segmentsToDriverString (_segments );
158+ final driver = _segmentsToDriverString ();
154159 super .value = TextEditingValue (
155160 text: driver,
156161 selection: TextSelection .collapsed (offset: driverOffset.clamp (0 , driver.length)),
@@ -162,7 +167,7 @@ class MentionTextController extends TextEditingController {
162167
163168 void loadFromEncodedString (String encodedString) {
164169 _segments = MentionSegmentSerializer .decode (encodedString);
165- final driver = _segmentsToDriverString (_segments );
170+ final driver = _segmentsToDriverString ();
166171 super .value = TextEditingValue (
167172 text: driver,
168173 selection: TextSelection .collapsed (offset: driver.length),
@@ -179,7 +184,7 @@ class MentionTextController extends TextEditingController {
179184 final end = selection.extentOffset.clamp (start, driverText.length);
180185 _replaceRangeInSegments (start, end, [MentionSegment (label: label)]);
181186 mentionState.value = null ;
182- final newDriver = _segmentsToDriverString (_segments );
187+ final newDriver = _segmentsToDriverString ();
183188 super .value = TextEditingValue (
184189 text: newDriver,
185190 selection: TextSelection .collapsed (offset: (start + 1 ).clamp (0 , newDriver.length)),
@@ -206,7 +211,7 @@ class MentionTextController extends TextEditingController {
206211 final start = math.min (sel.start, sel.end);
207212 final end = math.max (sel.start, sel.end);
208213 _replaceRangeInSegments (start, end, const []);
209- final driver = _segmentsToDriverString (_segments );
214+ final driver = _segmentsToDriverString ();
210215 super .value = TextEditingValue (
211216 text: driver,
212217 selection: TextSelection .collapsed (offset: start.clamp (0 , driver.length)),
@@ -226,7 +231,7 @@ class MentionTextController extends TextEditingController {
226231 final start = sel.isValid ? math.min (sel.start, sel.end) : text.length;
227232 final end = sel.isValid ? math.max (sel.start, sel.end) : text.length;
228233 _replaceRangeInSegments (start, end, inserted);
229- final driver = _segmentsToDriverString (_segments );
234+ final driver = _segmentsToDriverString ();
230235 final caret = (start + inserted.fold <int >(0 , (a, s) => a + s.driverLength)).clamp (0 , driver.length);
231236 super .value = TextEditingValue (
232237 text: driver,
@@ -260,7 +265,7 @@ class MentionTextController extends TextEditingController {
260265
261266 _replaceRangeInSegments (delStart, delEnd, inserted.isEmpty ? [] : [TextSegment (inserted)]);
262267
263- final driver = _segmentsToDriverString (_segments );
268+ final driver = _segmentsToDriverString ();
264269 final clampedSelection = _clampSelection (
265270 newValue.selection,
266271 driver.length,
@@ -355,10 +360,6 @@ class MentionTextController extends TextEditingController {
355360 return TextSpan (children: spans, style: baseStyle);
356361 }
357362
358- static String _segmentsToDriverString (List <Segment > segments) {
359- return segments.map ((s) => s.toDriverString (_marker)).join ();
360- }
361-
362363 List <Segment > _sliceSegments (int start, int end) {
363364 final out = < Segment > [];
364365 int currentOffset = 0 ;
0 commit comments