mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
Dart 3.9 / Flutter 3.35 [first LLM release] (#2714)
I got carried away with Gemini and basically rewrote CI and the release process for the new LLM reality. This work was largely completed by Gemini. - Bump all SDK versions to the current beta (3.9.0-0) - Run `flutter channel beta` - Wrote `ci_script.dart` to replace the bash scripts - Converted repository to pub workspace #2499 - Added llm.md and release.md - Added redirect for deprecated Samples Index ## Pre-launch Checklist - [x] I read the [Flutter Style Guide] _recently_, and have followed its advice. - [x] I signed the [CLA]. - [x] I read the [Contributors Guide]. - [x] I have added sample code updates to the [changelog]. - [x] I updated/added relevant documentation (doc comments with `///`).
This commit is contained in:
@@ -53,7 +53,9 @@ class AppStateWidgetState extends State<AppStateWidget> {
|
||||
toggleButtonsState: <ToggleButtonsState>{},
|
||||
);
|
||||
|
||||
void updateTextEditingDeltaHistory(List<TextEditingDelta> textEditingDeltas) {
|
||||
void updateTextEditingDeltaHistory(
|
||||
List<TextEditingDelta> textEditingDeltas,
|
||||
) {
|
||||
_data = _data.copyWith(
|
||||
textEditingDeltaHistory: <TextEditingDelta>[
|
||||
..._data.textEditingDeltaHistory,
|
||||
@@ -76,11 +78,12 @@ class AppStateWidgetState extends State<AppStateWidget> {
|
||||
|
||||
if (replacementStyles.isEmpty) {
|
||||
_data = _data.copyWith(
|
||||
toggleButtonsState: Set.from(_data.toggleButtonsState)..removeAll({
|
||||
ToggleButtonsState.bold,
|
||||
ToggleButtonsState.italic,
|
||||
ToggleButtonsState.underline,
|
||||
}),
|
||||
toggleButtonsState: Set.from(_data.toggleButtonsState)
|
||||
..removeAll({
|
||||
ToggleButtonsState.bold,
|
||||
ToggleButtonsState.italic,
|
||||
ToggleButtonsState.underline,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -180,7 +183,8 @@ class AppStateWidgetState extends State<AppStateWidget> {
|
||||
controller.applyReplacement(
|
||||
TextEditingInlineSpanReplacement(
|
||||
replacementRange,
|
||||
(string, range) => TextSpan(text: string, style: attributeMap[index]),
|
||||
(string, range) =>
|
||||
TextSpan(text: string, style: attributeMap[index]),
|
||||
true,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -10,8 +10,8 @@ class AppStateManager extends InheritedWidget {
|
||||
}) : _appState = state;
|
||||
|
||||
static AppStateManager of(BuildContext context) {
|
||||
final AppStateManager? result =
|
||||
context.dependOnInheritedWidgetOfExactType<AppStateManager>();
|
||||
final AppStateManager? result = context
|
||||
.dependOnInheritedWidgetOfExactType<AppStateManager>();
|
||||
assert(result != null, 'No AppStateManager found in context');
|
||||
return result!;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,9 @@ class _BasicTextFieldState extends State<BasicTextField> {
|
||||
TextSelection selection,
|
||||
SelectionChangedCause? cause,
|
||||
) {
|
||||
final bool willShowSelectionHandles = _shouldShowSelectionHandles(cause);
|
||||
final bool willShowSelectionHandles = _shouldShowSelectionHandles(
|
||||
cause,
|
||||
);
|
||||
if (willShowSelectionHandles != _showSelectionHandles) {
|
||||
setState(() {
|
||||
_showSelectionHandles = willShowSelectionHandles;
|
||||
@@ -98,16 +100,15 @@ class _BasicTextFieldState extends State<BasicTextField> {
|
||||
}
|
||||
|
||||
void _onDragUpdate(DragUpdateDetails details) {
|
||||
final Offset startOffset =
|
||||
_renderEditable.maxLines == 1
|
||||
? Offset(
|
||||
_renderEditable.offset.pixels - _dragStartViewportOffset,
|
||||
0.0,
|
||||
)
|
||||
: Offset(
|
||||
0.0,
|
||||
_renderEditable.offset.pixels - _dragStartViewportOffset,
|
||||
);
|
||||
final Offset startOffset = _renderEditable.maxLines == 1
|
||||
? Offset(
|
||||
_renderEditable.offset.pixels - _dragStartViewportOffset,
|
||||
0.0,
|
||||
)
|
||||
: Offset(
|
||||
0.0,
|
||||
_renderEditable.offset.pixels - _dragStartViewportOffset,
|
||||
);
|
||||
|
||||
_renderEditable.selectPositionAt(
|
||||
from: _startDetails.globalPosition - startOffset,
|
||||
@@ -134,7 +135,8 @@ class _BasicTextFieldState extends State<BasicTextField> {
|
||||
_textSelectionControls = cupertinoTextSelectionHandleControls;
|
||||
case TargetPlatform.macOS:
|
||||
// ignore: deprecated_member_use
|
||||
_textSelectionControls = cupertinoDesktopTextSelectionHandleControls;
|
||||
_textSelectionControls =
|
||||
cupertinoDesktopTextSelectionHandleControls;
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
// ignore: deprecated_member_use
|
||||
@@ -151,7 +153,8 @@ class _BasicTextFieldState extends State<BasicTextField> {
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onPanStart: (dragStartDetails) => _onDragStart(dragStartDetails),
|
||||
onPanUpdate: (dragUpdateDetails) => _onDragUpdate(dragUpdateDetails),
|
||||
onPanUpdate: (dragUpdateDetails) =>
|
||||
_onDragUpdate(dragUpdateDetails),
|
||||
onSecondaryTapDown: (secondaryTapDownDetails) {
|
||||
_renderEditable.selectWordsInRange(
|
||||
from: secondaryTapDownDetails.globalPosition,
|
||||
@@ -190,12 +193,12 @@ class _BasicTextFieldState extends State<BasicTextField> {
|
||||
);
|
||||
}
|
||||
},
|
||||
onLongPressEnd:
|
||||
(longPressEndDetails) => _textInputClient!.showToolbar(),
|
||||
onHorizontalDragStart:
|
||||
(dragStartDetails) => _onDragStart(dragStartDetails),
|
||||
onHorizontalDragUpdate:
|
||||
(dragUpdateDetails) => _onDragUpdate(dragUpdateDetails),
|
||||
onLongPressEnd: (longPressEndDetails) =>
|
||||
_textInputClient!.showToolbar(),
|
||||
onHorizontalDragStart: (dragStartDetails) =>
|
||||
_onDragStart(dragStartDetails),
|
||||
onHorizontalDragUpdate: (dragUpdateDetails) =>
|
||||
_onDragUpdate(dragUpdateDetails),
|
||||
child: SizedBox(
|
||||
height: double.infinity,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
|
||||
@@ -63,8 +63,9 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
with TextSelectionDelegate, TextInputClient, DeltaTextInputClient {
|
||||
final GlobalKey _textKey = GlobalKey();
|
||||
late AppStateWidgetState manager;
|
||||
final ClipboardStatusNotifier? _clipboardStatus =
|
||||
kIsWeb ? null : ClipboardStatusNotifier();
|
||||
final ClipboardStatusNotifier? _clipboardStatus = kIsWeb
|
||||
? null
|
||||
: ClipboardStatusNotifier();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -180,7 +181,9 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
}
|
||||
|
||||
@override
|
||||
void updateEditingValueWithDeltas(List<TextEditingDelta> textEditingDeltas) {
|
||||
void updateEditingValueWithDeltas(
|
||||
List<TextEditingDelta> textEditingDeltas,
|
||||
) {
|
||||
TextEditingValue value = _value;
|
||||
|
||||
for (final TextEditingDelta delta in textEditingDeltas) {
|
||||
@@ -339,40 +342,40 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
}
|
||||
|
||||
// These actions have yet to be implemented for this sample.
|
||||
static final Map<Type, Action<Intent>> _unsupportedActions =
|
||||
<Type, Action<Intent>>{
|
||||
DeleteToNextWordBoundaryIntent: DoNothingAction(consumesKey: false),
|
||||
DeleteToLineBreakIntent: DoNothingAction(consumesKey: false),
|
||||
ExtendSelectionToNextWordBoundaryIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
ExtendSelectionToNextParagraphBoundaryOrCaretLocationIntent:
|
||||
DoNothingAction(consumesKey: false),
|
||||
ExtendSelectionToLineBreakIntent: DoNothingAction(consumesKey: false),
|
||||
ExtendSelectionVerticallyToAdjacentLineIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
ExtendSelectionVerticallyToAdjacentPageIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
ExtendSelectionToNextParagraphBoundaryIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
ExtendSelectionToDocumentBoundaryIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
ExtendSelectionByPageIntent: DoNothingAction(consumesKey: false),
|
||||
ExpandSelectionToDocumentBoundaryIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
ExpandSelectionToLineBreakIntent: DoNothingAction(consumesKey: false),
|
||||
ScrollToDocumentBoundaryIntent: DoNothingAction(consumesKey: false),
|
||||
RedoTextIntent: DoNothingAction(consumesKey: false),
|
||||
ReplaceTextIntent: DoNothingAction(consumesKey: false),
|
||||
UndoTextIntent: DoNothingAction(consumesKey: false),
|
||||
UpdateSelectionIntent: DoNothingAction(consumesKey: false),
|
||||
TransposeCharactersIntent: DoNothingAction(consumesKey: false),
|
||||
};
|
||||
static final Map<Type, Action<Intent>>
|
||||
_unsupportedActions = <Type, Action<Intent>>{
|
||||
DeleteToNextWordBoundaryIntent: DoNothingAction(consumesKey: false),
|
||||
DeleteToLineBreakIntent: DoNothingAction(consumesKey: false),
|
||||
ExtendSelectionToNextWordBoundaryIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
ExtendSelectionToNextParagraphBoundaryOrCaretLocationIntent:
|
||||
DoNothingAction(consumesKey: false),
|
||||
ExtendSelectionToLineBreakIntent: DoNothingAction(consumesKey: false),
|
||||
ExtendSelectionVerticallyToAdjacentLineIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
ExtendSelectionVerticallyToAdjacentPageIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
ExtendSelectionToNextParagraphBoundaryIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
ExtendSelectionToDocumentBoundaryIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
ExtendSelectionByPageIntent: DoNothingAction(consumesKey: false),
|
||||
ExpandSelectionToDocumentBoundaryIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
ExpandSelectionToLineBreakIntent: DoNothingAction(consumesKey: false),
|
||||
ScrollToDocumentBoundaryIntent: DoNothingAction(consumesKey: false),
|
||||
RedoTextIntent: DoNothingAction(consumesKey: false),
|
||||
ReplaceTextIntent: DoNothingAction(consumesKey: false),
|
||||
UndoTextIntent: DoNothingAction(consumesKey: false),
|
||||
UpdateSelectionIntent: DoNothingAction(consumesKey: false),
|
||||
TransposeCharactersIntent: DoNothingAction(consumesKey: false),
|
||||
};
|
||||
|
||||
/// Keyboard text editing actions.
|
||||
// The Handling of the default text editing shortcuts with deltas
|
||||
@@ -388,9 +391,8 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
),
|
||||
ExtendSelectionByCharacterIntent:
|
||||
CallbackAction<ExtendSelectionByCharacterIntent>(
|
||||
onInvoke:
|
||||
(intent) =>
|
||||
_extendSelection(intent.forward, intent.collapseSelection),
|
||||
onInvoke: (intent) =>
|
||||
_extendSelection(intent.forward, intent.collapseSelection),
|
||||
),
|
||||
SelectAllTextIntent: CallbackAction<SelectAllTextIntent>(
|
||||
onInvoke: (intent) => selectAll(intent.cause),
|
||||
@@ -401,7 +403,9 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
PasteTextIntent: CallbackAction<PasteTextIntent>(
|
||||
onInvoke: (intent) => pasteText(intent.cause),
|
||||
),
|
||||
DoNothingAndStopPropagationTextIntent: DoNothingAction(consumesKey: false),
|
||||
DoNothingAndStopPropagationTextIntent: DoNothingAction(
|
||||
consumesKey: false,
|
||||
),
|
||||
..._unsupportedActions,
|
||||
};
|
||||
|
||||
@@ -458,28 +462,29 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
|
||||
if (collapseSelection) {
|
||||
if (!_selection.isCollapsed) {
|
||||
final int firstOffset =
|
||||
_selection.isNormalized ? _selection.start : _selection.end;
|
||||
final int lastOffset =
|
||||
_selection.isNormalized ? _selection.end : _selection.start;
|
||||
final int firstOffset = _selection.isNormalized
|
||||
? _selection.start
|
||||
: _selection.end;
|
||||
final int lastOffset = _selection.isNormalized
|
||||
? _selection.end
|
||||
: _selection.start;
|
||||
selection = TextSelection.collapsed(
|
||||
offset: forward ? lastOffset : firstOffset,
|
||||
);
|
||||
} else {
|
||||
if (forward && _selection.baseOffset == _value.text.length) return;
|
||||
if (!forward && _selection.baseOffset == 0) return;
|
||||
final int adjustment =
|
||||
forward
|
||||
? _value.text
|
||||
.substring(_selection.baseOffset)
|
||||
.characters
|
||||
.first
|
||||
.length
|
||||
: -_value.text
|
||||
.substring(0, _selection.baseOffset)
|
||||
.characters
|
||||
.last
|
||||
.length;
|
||||
final int adjustment = forward
|
||||
? _value.text
|
||||
.substring(_selection.baseOffset)
|
||||
.characters
|
||||
.first
|
||||
.length
|
||||
: -_value.text
|
||||
.substring(0, _selection.baseOffset)
|
||||
.characters
|
||||
.last
|
||||
.length;
|
||||
selection = TextSelection.collapsed(
|
||||
offset: _selection.baseOffset + adjustment,
|
||||
);
|
||||
@@ -487,18 +492,17 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
} else {
|
||||
if (forward && _selection.extentOffset == _value.text.length) return;
|
||||
if (!forward && _selection.extentOffset == 0) return;
|
||||
final int adjustment =
|
||||
forward
|
||||
? _value.text
|
||||
.substring(_selection.baseOffset)
|
||||
.characters
|
||||
.first
|
||||
.length
|
||||
: -_value.text
|
||||
.substring(0, _selection.baseOffset)
|
||||
.characters
|
||||
.last
|
||||
.length;
|
||||
final int adjustment = forward
|
||||
? _value.text
|
||||
.substring(_selection.baseOffset)
|
||||
.characters
|
||||
.first
|
||||
.length
|
||||
: -_value.text
|
||||
.substring(0, _selection.baseOffset)
|
||||
.characters
|
||||
.last
|
||||
.length;
|
||||
selection = TextSelection(
|
||||
baseOffset: _selection.baseOffset,
|
||||
extentOffset: _selection.extentOffset + adjustment,
|
||||
@@ -578,7 +582,9 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
|
||||
void _updateCaretRectIfNeeded() {
|
||||
final TextSelection? selection = renderEditable.selection;
|
||||
if (selection == null || !selection.isValid || !selection.isCollapsed) {
|
||||
if (selection == null ||
|
||||
!selection.isValid ||
|
||||
!selection.isCollapsed) {
|
||||
return;
|
||||
}
|
||||
final TextPosition currentTextPosition = TextPosition(
|
||||
@@ -691,7 +697,9 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
final TextSelection pasteRange = textEditingValue.selection;
|
||||
if (!pasteRange.isValid) return;
|
||||
|
||||
final ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
|
||||
final ClipboardData? data = await Clipboard.getData(
|
||||
Clipboard.kTextPlain,
|
||||
);
|
||||
if (data == null) return;
|
||||
|
||||
// After the paste, the cursor should be collapsed and located after the
|
||||
@@ -846,7 +854,8 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
requestKeyboard();
|
||||
}
|
||||
}
|
||||
if (widget.selectionControls == null && widget.contextMenuBuilder == null) {
|
||||
if (widget.selectionControls == null &&
|
||||
widget.contextMenuBuilder == null) {
|
||||
_selectionOverlay?.dispose();
|
||||
_selectionOverlay = null;
|
||||
} else {
|
||||
@@ -891,41 +900,43 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
onSelectionHandleTapped: () {
|
||||
_toggleToolbar();
|
||||
},
|
||||
contextMenuBuilder:
|
||||
widget.contextMenuBuilder == null || kIsWeb
|
||||
? null
|
||||
: (context) {
|
||||
return widget.contextMenuBuilder!(
|
||||
context,
|
||||
_clipboardStatus!.value,
|
||||
copyEnabled
|
||||
? () => copySelection(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
cutEnabled
|
||||
? () => cutSelection(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
pasteEnabled
|
||||
? () => pasteText(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
selectAllEnabled
|
||||
? () => selectAll(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
lookUpEnabled
|
||||
? () => _lookUpSelection(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
liveTextInputEnabled
|
||||
? () => _startLiveTextInput(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
searchWebEnabled
|
||||
? () =>
|
||||
_searchWebForSelection(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
shareEnabled
|
||||
? () => _shareSelection(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
_contextMenuAnchors,
|
||||
);
|
||||
},
|
||||
contextMenuBuilder: widget.contextMenuBuilder == null || kIsWeb
|
||||
? null
|
||||
: (context) {
|
||||
return widget.contextMenuBuilder!(
|
||||
context,
|
||||
_clipboardStatus!.value,
|
||||
copyEnabled
|
||||
? () => copySelection(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
cutEnabled
|
||||
? () => cutSelection(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
pasteEnabled
|
||||
? () => pasteText(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
selectAllEnabled
|
||||
? () => selectAll(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
lookUpEnabled
|
||||
? () => _lookUpSelection(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
liveTextInputEnabled
|
||||
? () => _startLiveTextInput(
|
||||
SelectionChangedCause.toolbar,
|
||||
)
|
||||
: null,
|
||||
searchWebEnabled
|
||||
? () => _searchWebForSelection(
|
||||
SelectionChangedCause.toolbar,
|
||||
)
|
||||
: null,
|
||||
shareEnabled
|
||||
? () => _shareSelection(SelectionChangedCause.toolbar)
|
||||
: null,
|
||||
_contextMenuAnchors,
|
||||
);
|
||||
},
|
||||
magnifierConfiguration: TextMagnifierConfiguration.disabled,
|
||||
);
|
||||
|
||||
@@ -933,8 +944,8 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
}
|
||||
|
||||
void _toggleToolbar() {
|
||||
final TextSelectionOverlay selectionOverlay =
|
||||
_selectionOverlay ??= _createSelectionOverlay();
|
||||
final TextSelectionOverlay selectionOverlay = _selectionOverlay ??=
|
||||
_createSelectionOverlay();
|
||||
|
||||
if (selectionOverlay.toolbarIsVisible) {
|
||||
hideToolbar(false);
|
||||
@@ -971,7 +982,9 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
final InlineSpan span = renderEditable.text!;
|
||||
final String prevText = span.toPlainText();
|
||||
final String currText = textEditingValue.text;
|
||||
if (prevText != currText || !selection.isValid || selection.isCollapsed) {
|
||||
if (prevText != currText ||
|
||||
!selection.isValid ||
|
||||
selection.isCollapsed) {
|
||||
return _GlyphHeights(
|
||||
start: renderEditable.preferredLineHeight,
|
||||
end: renderEditable.preferredLineHeight,
|
||||
@@ -981,12 +994,13 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
final String selectedGraphemes = selection.textInside(currText);
|
||||
final int firstSelectedGraphemeExtent =
|
||||
selectedGraphemes.characters.first.length;
|
||||
final Rect? startCharacterRect = renderEditable.getRectForComposingRange(
|
||||
TextRange(
|
||||
start: selection.start,
|
||||
end: selection.start + firstSelectedGraphemeExtent,
|
||||
),
|
||||
);
|
||||
final Rect? startCharacterRect = renderEditable
|
||||
.getRectForComposingRange(
|
||||
TextRange(
|
||||
start: selection.start,
|
||||
end: selection.start + firstSelectedGraphemeExtent,
|
||||
),
|
||||
);
|
||||
final int lastSelectedGraphemeExtent =
|
||||
selectedGraphemes.characters.last.length;
|
||||
final Rect? endCharacterRect = renderEditable.getRectForComposingRange(
|
||||
@@ -996,7 +1010,8 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
),
|
||||
);
|
||||
return _GlyphHeights(
|
||||
start: startCharacterRect?.height ?? renderEditable.preferredLineHeight,
|
||||
start:
|
||||
startCharacterRect?.height ?? renderEditable.preferredLineHeight,
|
||||
end: endCharacterRect?.height ?? renderEditable.preferredLineHeight,
|
||||
);
|
||||
}
|
||||
@@ -1023,8 +1038,9 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
|
||||
/// For OCR Support.
|
||||
/// Detects whether the Live Text input is enabled.
|
||||
final LiveTextInputStatusNotifier? _liveTextInputStatus =
|
||||
kIsWeb ? null : LiveTextInputStatusNotifier();
|
||||
final LiveTextInputStatusNotifier? _liveTextInputStatus = kIsWeb
|
||||
? null
|
||||
: LiveTextInputStatusNotifier();
|
||||
|
||||
@override
|
||||
bool get liveTextInputEnabled {
|
||||
@@ -1079,7 +1095,9 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
}
|
||||
|
||||
return !textEditingValue.selection.isCollapsed &&
|
||||
textEditingValue.selection.textInside(textEditingValue.text).trim() !=
|
||||
textEditingValue.selection
|
||||
.textInside(textEditingValue.text)
|
||||
.trim() !=
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1142,7 +1160,8 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
startHandleLayerLink: _startHandleLayerLink,
|
||||
endHandleLayerLink: _endHandleLayerLink,
|
||||
inlineSpan: _buildTextSpan(),
|
||||
value: _value, // We pass value.selection to RenderEditable.
|
||||
value:
|
||||
_value, // We pass value.selection to RenderEditable.
|
||||
cursorColor: Colors.blue,
|
||||
backgroundCursorColor: Colors.grey[100],
|
||||
showCursor: ValueNotifier<bool>(_hasFocus),
|
||||
@@ -1159,7 +1178,9 @@ class BasicTextInputClientState extends State<BasicTextInputClient>
|
||||
textAlign: TextAlign.left,
|
||||
textDirection: _textDirection,
|
||||
locale: Localizations.maybeLocaleOf(context),
|
||||
textHeightBehavior: DefaultTextHeightBehavior.maybeOf(context),
|
||||
textHeightBehavior: DefaultTextHeightBehavior.maybeOf(
|
||||
context,
|
||||
),
|
||||
textWidthBasis: TextWidthBasis.parent,
|
||||
obscuringCharacter: '•',
|
||||
obscureText:
|
||||
@@ -1321,7 +1342,10 @@ class _Editable extends MultiChildRenderObjectWidget {
|
||||
}
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderEditable renderObject) {
|
||||
void updateRenderObject(
|
||||
BuildContext context,
|
||||
RenderEditable renderObject,
|
||||
) {
|
||||
renderObject
|
||||
..text = inlineSpan
|
||||
..cursorColor = cursorColor
|
||||
|
||||
@@ -31,10 +31,9 @@ class FormattingToolbar extends StatelessWidget {
|
||||
ToggleButtonsState.underline,
|
||||
),
|
||||
],
|
||||
onPressed:
|
||||
(index) => AppStateWidget.of(
|
||||
context,
|
||||
).updateToggleButtonsStateOnButtonPressed(index),
|
||||
onPressed: (index) => AppStateWidget.of(
|
||||
context,
|
||||
).updateToggleButtonsStateOnButtonPressed(index),
|
||||
children: const [
|
||||
Icon(Icons.format_bold),
|
||||
Icon(Icons.format_italic),
|
||||
|
||||
@@ -49,8 +49,9 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
_replacementTextEditingController =
|
||||
AppStateManager.of(context).appState.replacementsController;
|
||||
_replacementTextEditingController = AppStateManager.of(
|
||||
context,
|
||||
).appState.replacementsController;
|
||||
}
|
||||
|
||||
static Route<Object?> _aboutDialogBuilder(
|
||||
@@ -67,11 +68,10 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
' more powerful rich text editing applications such as this small example. This feature is supported on all platforms.';
|
||||
return DialogRoute<void>(
|
||||
context: context,
|
||||
builder:
|
||||
(context) => const AlertDialog(
|
||||
title: Center(child: Text('About')),
|
||||
content: Text(aboutContent),
|
||||
),
|
||||
builder: (context) => const AlertDialog(
|
||||
title: Center(child: Text('About')),
|
||||
content: Text(aboutContent),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,10 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 35.0),
|
||||
child: BasicTextField(
|
||||
controller: _replacementTextEditingController,
|
||||
style: const TextStyle(fontSize: 18.0, color: Colors.black),
|
||||
style: const TextStyle(
|
||||
fontSize: 18.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
focusNode: _focusNode,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -41,7 +41,11 @@ typedef InlineSpanGenerator = InlineSpan Function(String, TextRange);
|
||||
class TextEditingInlineSpanReplacement {
|
||||
/// Constructs a replacement that replaces matches of the [TextRange] with the
|
||||
/// output of the [generator].
|
||||
TextEditingInlineSpanReplacement(this.range, this.generator, this.expand);
|
||||
TextEditingInlineSpanReplacement(
|
||||
this.range,
|
||||
this.generator,
|
||||
this.expand,
|
||||
);
|
||||
|
||||
/// The [TextRange] to replace.
|
||||
///
|
||||
@@ -54,7 +58,9 @@ class TextEditingInlineSpanReplacement {
|
||||
|
||||
bool expand;
|
||||
|
||||
TextEditingInlineSpanReplacement? onDelete(TextEditingDeltaDeletion delta) {
|
||||
TextEditingInlineSpanReplacement? onDelete(
|
||||
TextEditingDeltaDeletion delta,
|
||||
) {
|
||||
final TextRange deletedRange = delta.deletedRange;
|
||||
final int deletedLength = delta.textDeleted.length;
|
||||
|
||||
@@ -75,7 +81,10 @@ class TextEditingInlineSpanReplacement {
|
||||
} else if (range.start < deletedRange.start &&
|
||||
range.end > deletedRange.end) {
|
||||
return copy(
|
||||
range: TextRange(start: range.start, end: range.end - deletedLength),
|
||||
range: TextRange(
|
||||
start: range.start,
|
||||
end: range.end - deletedLength,
|
||||
),
|
||||
);
|
||||
} else if (range.start >= deletedRange.start &&
|
||||
range.end <= deletedRange.end) {
|
||||
@@ -90,7 +99,9 @@ class TextEditingInlineSpanReplacement {
|
||||
);
|
||||
} else if (range.end <= deletedRange.start &&
|
||||
range.end < deletedRange.end) {
|
||||
return copy(range: TextRange(start: range.start, end: range.end));
|
||||
return copy(
|
||||
range: TextRange(start: range.start, end: range.end),
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -105,24 +116,36 @@ class TextEditingInlineSpanReplacement {
|
||||
if (range.end == insertionOffset) {
|
||||
if (expand) {
|
||||
return copy(
|
||||
range: TextRange(start: range.start, end: range.end + insertedLength),
|
||||
range: TextRange(
|
||||
start: range.start,
|
||||
end: range.end + insertedLength,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return copy(range: TextRange(start: range.start, end: range.end));
|
||||
return copy(
|
||||
range: TextRange(start: range.start, end: range.end),
|
||||
);
|
||||
}
|
||||
}
|
||||
if (range.start < insertionOffset && range.end < insertionOffset) {
|
||||
return copy(range: TextRange(start: range.start, end: range.end));
|
||||
} else if (range.start >= insertionOffset && range.end > insertionOffset) {
|
||||
return copy(
|
||||
range: TextRange(start: range.start, end: range.end),
|
||||
);
|
||||
} else if (range.start >= insertionOffset &&
|
||||
range.end > insertionOffset) {
|
||||
return copy(
|
||||
range: TextRange(
|
||||
start: range.start + insertedLength,
|
||||
end: range.end + insertedLength,
|
||||
),
|
||||
);
|
||||
} else if (range.start < insertionOffset && range.end > insertionOffset) {
|
||||
} else if (range.start < insertionOffset &&
|
||||
range.end > insertionOffset) {
|
||||
return copy(
|
||||
range: TextRange(start: range.start, end: range.end + insertedLength),
|
||||
range: TextRange(
|
||||
start: range.start,
|
||||
end: range.end + insertedLength,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -139,13 +162,13 @@ class TextEditingInlineSpanReplacement {
|
||||
delta.replacementText.length > delta.textReplaced.length;
|
||||
final bool replacementEqualLength =
|
||||
delta.replacementText.length == delta.textReplaced.length;
|
||||
final int changedOffset =
|
||||
replacementShortenedText
|
||||
? delta.textReplaced.length - delta.replacementText.length
|
||||
: delta.replacementText.length - delta.textReplaced.length;
|
||||
final int changedOffset = replacementShortenedText
|
||||
? delta.textReplaced.length - delta.replacementText.length
|
||||
: delta.replacementText.length - delta.textReplaced.length;
|
||||
|
||||
if (range.start >= replacedRange.start &&
|
||||
(range.start < replacedRange.end && range.end > replacedRange.end)) {
|
||||
(range.start < replacedRange.end &&
|
||||
range.end > replacedRange.end)) {
|
||||
if (replacementShortenedText) {
|
||||
return [
|
||||
copy(
|
||||
@@ -166,20 +189,26 @@ class TextEditingInlineSpanReplacement {
|
||||
];
|
||||
} else if (replacementEqualLength) {
|
||||
return [
|
||||
copy(range: TextRange(start: replacedRange.end, end: range.end)),
|
||||
copy(
|
||||
range: TextRange(start: replacedRange.end, end: range.end),
|
||||
),
|
||||
];
|
||||
}
|
||||
} else if ((range.start < replacedRange.start &&
|
||||
range.end > replacedRange.start) &&
|
||||
range.end <= replacedRange.end) {
|
||||
return [
|
||||
copy(range: TextRange(start: range.start, end: replacedRange.start)),
|
||||
copy(
|
||||
range: TextRange(start: range.start, end: replacedRange.start),
|
||||
),
|
||||
];
|
||||
} else if (range.start < replacedRange.start &&
|
||||
range.end > replacedRange.end) {
|
||||
if (replacementShortenedText) {
|
||||
return [
|
||||
copy(range: TextRange(start: range.start, end: replacedRange.start)),
|
||||
copy(
|
||||
range: TextRange(start: range.start, end: replacedRange.start),
|
||||
),
|
||||
copy(
|
||||
range: TextRange(
|
||||
start: replacedRange.end - changedOffset,
|
||||
@@ -189,7 +218,9 @@ class TextEditingInlineSpanReplacement {
|
||||
];
|
||||
} else if (replacementLengthenedText) {
|
||||
return [
|
||||
copy(range: TextRange(start: range.start, end: replacedRange.start)),
|
||||
copy(
|
||||
range: TextRange(start: range.start, end: replacedRange.start),
|
||||
),
|
||||
copy(
|
||||
range: TextRange(
|
||||
start: replacedRange.end + changedOffset,
|
||||
@@ -199,8 +230,12 @@ class TextEditingInlineSpanReplacement {
|
||||
];
|
||||
} else if (replacementEqualLength) {
|
||||
return [
|
||||
copy(range: TextRange(start: range.start, end: replacedRange.start)),
|
||||
copy(range: TextRange(start: replacedRange.end, end: range.end)),
|
||||
copy(
|
||||
range: TextRange(start: range.start, end: replacedRange.start),
|
||||
),
|
||||
copy(
|
||||
range: TextRange(start: replacedRange.end, end: range.end),
|
||||
),
|
||||
];
|
||||
}
|
||||
} else if (range.start >= replacedRange.start &&
|
||||
@@ -232,7 +267,11 @@ class TextEditingInlineSpanReplacement {
|
||||
}
|
||||
} else if (range.end <= replacedRange.start &&
|
||||
range.end < replacedRange.end) {
|
||||
return [copy(range: TextRange(start: range.start, end: range.end))];
|
||||
return [
|
||||
copy(
|
||||
range: TextRange(start: range.start, end: range.end),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -250,15 +289,23 @@ class TextEditingInlineSpanReplacement {
|
||||
return this;
|
||||
}
|
||||
|
||||
List<TextEditingInlineSpanReplacement>? removeRange(TextRange removalRange) {
|
||||
List<TextEditingInlineSpanReplacement>? removeRange(
|
||||
TextRange removalRange,
|
||||
) {
|
||||
if (range.start >= removalRange.start &&
|
||||
(range.start < removalRange.end && range.end > removalRange.end)) {
|
||||
return [copy(range: TextRange(start: removalRange.end, end: range.end))];
|
||||
return [
|
||||
copy(
|
||||
range: TextRange(start: removalRange.end, end: range.end),
|
||||
),
|
||||
];
|
||||
} else if ((range.start < removalRange.start &&
|
||||
range.end > removalRange.start) &&
|
||||
range.end <= removalRange.end) {
|
||||
return [
|
||||
copy(range: TextRange(start: range.start, end: removalRange.start)),
|
||||
copy(
|
||||
range: TextRange(start: range.start, end: removalRange.start),
|
||||
),
|
||||
];
|
||||
} else if (range.start < removalRange.start &&
|
||||
range.end > removalRange.end) {
|
||||
@@ -267,7 +314,9 @@ class TextEditingInlineSpanReplacement {
|
||||
range: TextRange(start: range.start, end: removalRange.start),
|
||||
expand: removalRange.isCollapsed ? false : expand,
|
||||
),
|
||||
copy(range: TextRange(start: removalRange.end, end: range.end)),
|
||||
copy(
|
||||
range: TextRange(start: removalRange.end, end: range.end),
|
||||
),
|
||||
];
|
||||
} else if (range.start >= removalRange.start &&
|
||||
range.end <= removalRange.end) {
|
||||
@@ -278,7 +327,8 @@ class TextEditingInlineSpanReplacement {
|
||||
} else if (range.end <= removalRange.start &&
|
||||
range.end < removalRange.end) {
|
||||
return [this];
|
||||
} else if (removalRange.isCollapsed && range.end == removalRange.start) {
|
||||
} else if (removalRange.isCollapsed &&
|
||||
range.end == removalRange.start) {
|
||||
return [this];
|
||||
}
|
||||
|
||||
@@ -453,7 +503,9 @@ class ReplacementTextEditingController extends TextEditingController {
|
||||
required bool withComposing,
|
||||
}) {
|
||||
assert(
|
||||
!value.composing.isValid || !withComposing || value.isComposingRangeValid,
|
||||
!value.composing.isValid ||
|
||||
!withComposing ||
|
||||
value.isComposingRangeValid,
|
||||
);
|
||||
|
||||
// Keep a mapping of TextRanges to the InlineSpan to replace it with.
|
||||
@@ -467,7 +519,10 @@ class ReplacementTextEditingController extends TextEditingController {
|
||||
in replacements!) {
|
||||
_addToMappingWithOverlaps(
|
||||
replacement.generator,
|
||||
TextRange(start: replacement.range.start, end: replacement.range.end),
|
||||
TextRange(
|
||||
start: replacement.range.start,
|
||||
end: replacement.range.end,
|
||||
),
|
||||
rangeSpanMapping,
|
||||
value.text,
|
||||
);
|
||||
@@ -484,12 +539,11 @@ class ReplacementTextEditingController extends TextEditingController {
|
||||
withComposing) {
|
||||
_addToMappingWithOverlaps(
|
||||
(value, range) {
|
||||
final TextStyle composingStyle =
|
||||
style != null
|
||||
? style.merge(
|
||||
const TextStyle(decoration: TextDecoration.underline),
|
||||
)
|
||||
: const TextStyle(decoration: TextDecoration.underline);
|
||||
final TextStyle composingStyle = style != null
|
||||
? style.merge(
|
||||
const TextStyle(decoration: TextDecoration.underline),
|
||||
)
|
||||
: const TextStyle(decoration: TextDecoration.underline);
|
||||
return TextSpan(style: composingStyle, text: value);
|
||||
},
|
||||
value.composing,
|
||||
@@ -509,7 +563,9 @@ class ReplacementTextEditingController extends TextEditingController {
|
||||
for (final TextRange range in sortedRanges) {
|
||||
if (range.start > previousEndIndex) {
|
||||
spans.add(
|
||||
TextSpan(text: value.text.substring(previousEndIndex, range.start)),
|
||||
TextSpan(
|
||||
text: value.text.substring(previousEndIndex, range.start),
|
||||
),
|
||||
);
|
||||
}
|
||||
spans.add(rangeSpanMapping[range]!);
|
||||
@@ -624,8 +680,9 @@ class ReplacementTextEditingController extends TextEditingController {
|
||||
}
|
||||
|
||||
Set<TextStyle> styles = <TextStyle>{};
|
||||
List<int> otherEndPoints =
|
||||
endPoints.getRange(1, endPoints.length).toList();
|
||||
List<int> otherEndPoints = endPoints
|
||||
.getRange(1, endPoints.length)
|
||||
.toList();
|
||||
for (int i = 0; i < endPoints.length - 1; i++) {
|
||||
styles = styles.difference(end[endPoints[i]]!);
|
||||
styles.addAll(start[endPoints[i]]!);
|
||||
@@ -671,7 +728,8 @@ class ReplacementTextEditingController extends TextEditingController {
|
||||
final List<TextEditingInlineSpanReplacement> toRemove = [];
|
||||
final List<TextEditingInlineSpanReplacement> toAdd = [];
|
||||
|
||||
for (final TextEditingInlineSpanReplacement replacement in replacements!) {
|
||||
for (final TextEditingInlineSpanReplacement replacement
|
||||
in replacements!) {
|
||||
if (replacement.range.end == selection.start) {
|
||||
TextStyle? replacementStyle =
|
||||
(replacement.generator('', const TextRange.collapsed(0))
|
||||
@@ -689,7 +747,8 @@ class ReplacementTextEditingController extends TextEditingController {
|
||||
replacements!.remove(replacementToRemove);
|
||||
}
|
||||
|
||||
for (final TextEditingInlineSpanReplacement replacementWithExpandDisabled
|
||||
for (final TextEditingInlineSpanReplacement
|
||||
replacementWithExpandDisabled
|
||||
in toAdd) {
|
||||
replacements!.add(replacementWithExpandDisabled);
|
||||
}
|
||||
@@ -704,7 +763,8 @@ class ReplacementTextEditingController extends TextEditingController {
|
||||
// should be enabled.
|
||||
final List<TextStyle> stylesAtSelection = <TextStyle>[];
|
||||
|
||||
for (final TextEditingInlineSpanReplacement replacement in replacements!) {
|
||||
for (final TextEditingInlineSpanReplacement replacement
|
||||
in replacements!) {
|
||||
if (selection.isCollapsed) {
|
||||
if (math.max(replacement.range.start, selection.start) <=
|
||||
math.min(replacement.range.end, selection.end)) {
|
||||
@@ -738,7 +798,10 @@ class ReplacementTextEditingController extends TextEditingController {
|
||||
return stylesAtSelection;
|
||||
}
|
||||
|
||||
void removeReplacementsAtRange(TextRange removalRange, TextStyle? attribute) {
|
||||
void removeReplacementsAtRange(
|
||||
TextRange removalRange,
|
||||
TextStyle? attribute,
|
||||
) {
|
||||
final List<TextEditingInlineSpanReplacement> toRemove = [];
|
||||
final List<TextEditingInlineSpanReplacement> toAdd = [];
|
||||
|
||||
@@ -755,8 +818,8 @@ class ReplacementTextEditingController extends TextEditingController {
|
||||
math.min(replacement.range.end, removalRange.end)) &&
|
||||
replacementStyle != null) {
|
||||
if (replacementStyle == attribute!) {
|
||||
List<TextEditingInlineSpanReplacement>? newReplacements = replacement
|
||||
.removeRange(removalRange);
|
||||
List<TextEditingInlineSpanReplacement>? newReplacements =
|
||||
replacement.removeRange(removalRange);
|
||||
|
||||
if (newReplacements != null) {
|
||||
if (newReplacements.length == 1) {
|
||||
@@ -782,7 +845,8 @@ class ReplacementTextEditingController extends TextEditingController {
|
||||
replacements!.add(replacementToAdd);
|
||||
}
|
||||
|
||||
for (TextEditingInlineSpanReplacement replacementToRemove in toRemove) {
|
||||
for (TextEditingInlineSpanReplacement replacementToRemove
|
||||
in toRemove) {
|
||||
replacements!.remove(replacementToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,10 @@ class TextEditingDeltaHistoryView extends StatelessWidget {
|
||||
|
||||
Widget _buildTextEditingDeltaViewHeader() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 35.0, vertical: 10.0),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 35.0,
|
||||
vertical: 10.0,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
@@ -186,9 +189,15 @@ class TextEditingDeltaView extends StatelessWidget {
|
||||
children: [
|
||||
Expanded(child: Text(deltaType)),
|
||||
Expanded(child: Text(deltaText)),
|
||||
Expanded(child: Text('(${deltaRange.start}, ${deltaRange.end})')),
|
||||
Expanded(child: Text('(${newSelection.start}, ${newSelection.end})')),
|
||||
Expanded(child: Text('(${newComposing.start}, ${newComposing.end})')),
|
||||
Expanded(
|
||||
child: Text('(${deltaRange.start}, ${deltaRange.end})'),
|
||||
),
|
||||
Expanded(
|
||||
child: Text('(${newSelection.start}, ${newSelection.end})'),
|
||||
),
|
||||
Expanded(
|
||||
child: Text('(${newComposing.start}, ${newComposing.end})'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user