From b039a97768516a73f454a356055a77448febd43c Mon Sep 17 00:00:00 2001 From: Eimji Date: Wed, 9 Nov 2022 16:46:22 +0100 Subject: [PATCH 1/2] Fix warnings, erros, iOS Keyboard entry, backspace for Android, unicode char --- .DS_Store | Bin 0 -> 6148 bytes lib/.DS_Store | Bin 0 -> 6148 bytes lib/src/.DS_Store | Bin 0 -> 6148 bytes lib/src/chips_input.dart | 136 +++++++++++------------- lib/src/suggestions_box_controller.dart | 2 +- lib/src/text_cursor.dart | 9 +- 6 files changed, 68 insertions(+), 79 deletions(-) create mode 100644 .DS_Store create mode 100644 lib/.DS_Store create mode 100644 lib/src/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..64e3d040bba1f41d084f6f59f986db6ed7478f77 GIT binary patch literal 6148 zcmeHKTZ_{`6h6~No7xrn;DSB~0bfhq7FQR1slA{JUSPB6gGx;{!3}0Jp-HV$3VGN6 zB0l;<^uPF|-&_`&wEHB8$eeQKo6Grfk}s2)4iT~8Jm?X%iO7Zvw637oVq#qQhShXW z3&`X(K2k;zd`f&H+H@ENi~|3f0^-}Cfg!uwg_H7KMHGDC{H2+Ps9UO7u0F%kKd zs4v^2{6&`PJO1XUag^nIdp}sMZe65AEF#~Q zX;A-KVOW@QA@bzqJ7PC0acCO*a|QHtv&9-<%qUSk!4w_+j*c5>EEFm_F@5-8Iy2KJ6ehFd`i=}I zHc)6vqkvJMtUz5g+hYHpTzvj7lT6DfU=;YT6kyia9S`wHdT-r$II-6{@HcQ_BCb#< lDJb-IEGuFwz7Cg$F-KH@1C513^uWv?0V#tii~@gEf!|FOz=Hq) literal 0 HcmV?d00001 diff --git a/lib/.DS_Store b/lib/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..142ba3fcc18feda70f5903f712dd6e686eab648c GIT binary patch literal 6148 zcmeHKO>fgc5S>i|byOkc08+WF)N53dh(aYUCX_?3xPk+qV8?-47;j`dtu;{ADz!3UirJ0gG#oD5V(lTc71-n&c)yF8?^+ zpo42Ku-nKhY5H5#bJQHUAXqn1$+DXJw!SCxJge%#;D>6pJ9qBx1$)7M@IJaQ%czd) zMKzAgxBPZ)OrC7)IC-7TmXqH77pAD=teBNHAxmcndG{tOQnMVJMUhrEH*yt0H|S1! z4_B+vlc#+>8Xd3udNmxLJnrk`;mLa44IUgmdiHAaIsa0aOWR>m_{pu@^SFU47=F-S zqq4|N@d=(y^d?GB7!U@8ft_K%FHph$&h$t+A`A!vyTSmk4;soCdTbopr2~b%0s#3K zX$3YP2{}i53_UguQ3Fvf73flxzhWqt4!`zsp~uFdODE+oAIg7O`5TI|Uq}1ehLZ{% zN+}Eo1GgDyyVoA?|1bZ3|G%9iZ^D2u@Lw^YI;YX;7(?=V>(=0Suhq~GP!^7B9NwhB iuv;-=c`H7ET7h4)0SrAh4&i~wLBP@=g)s0>8Tbj5nrR^b literal 0 HcmV?d00001 diff --git a/lib/src/.DS_Store b/lib/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..8211f3b3e483e2011130ee350c2a1be61d016c62 GIT binary patch literal 6148 zcmeHKu};H441IzO(Uojk%}e~V?K+&gJ+*XZAn*zkR9DU z=gxk)JSlfE0Gaj6E1&={Wm6P&MofoCr;a@Mm?*}v!97-Z!5aMt(O(?WwHK)H%yqA^ zz5WgtSmF_{=x&;}S~Ts#Vu4%Y<%b*nGv@Vp;#Je@$kb8;r$fB>5P$Ml z@gnwg@+S+2lo_KB1ww&c1+@016?*<(^OG4Z@+~B~P#_feuL{Uyem9@-?fh*0@t%6t wCbkDQHH{n8q0!&@3E++HBd0c*=ac%3D; = FutureOr> Function(String query); typedef ChipSelected = void Function(T data, bool selected); -typedef ChipsBuilder = Widget Function( - BuildContext context, ChipsInputState state, T data); +typedef ChipsBuilder = Widget Function(BuildContext context, ChipsInputState state, T data); const kObjectReplacementChar = 0xFFFD; @@ -19,9 +18,7 @@ extension on TextEditingValue { text.codeUnits.where((ch) => ch != kObjectReplacementChar), ); - List get replacementCharacters => text.codeUnits - .where((ch) => ch == kObjectReplacementChar) - .toList(growable: false); + List get replacementCharacters => text.codeUnits.where((ch) => ch == kObjectReplacementChar).toList(growable: false); int get replacementCharactersCount => replacementCharacters.length; } @@ -84,12 +81,10 @@ class ChipsInput extends StatefulWidget { ChipsInputState createState() => ChipsInputState(); } -class ChipsInputState extends State> - implements TextInputClient { +class ChipsInputState extends State> implements TextInputClient { Set _chips = {}; List? _suggestions; - final StreamController?> _suggestionsStreamController = - StreamController?>.broadcast(); + final StreamController?> _suggestionsStreamController = StreamController?>.broadcast(); int _searchId = 0; TextEditingValue _value = const TextEditingValue(); TextInputConnection? _textInputConnection; @@ -107,15 +102,12 @@ class ChipsInputState extends State> textCapitalization: widget.textCapitalization, ); - bool get _hasInputConnection => - _textInputConnection != null && _textInputConnection!.attached; + bool get _hasInputConnection => _textInputConnection != null && _textInputConnection!.attached; - bool get _hasReachedMaxChips => - widget.maxChips != null && _chips.length >= widget.maxChips!; + bool get _hasReachedMaxChips => widget.maxChips != null && _chips.length >= widget.maxChips!; FocusNode? _focusNode; - FocusNode get _effectiveFocusNode => - widget.focusNode ?? (_focusNode ??= FocusNode()); + FocusNode get _effectiveFocusNode => widget.focusNode ?? (_focusNode ??= FocusNode()); late FocusAttachment _nodeAttachment; RenderBox? get renderBox => context.findRenderObject() as RenderBox?; @@ -126,9 +118,7 @@ class ChipsInputState extends State> void initState() { super.initState(); _chips.addAll(widget.initialValue); - _suggestions = widget.initialSuggestions - ?.where((r) => !_chips.contains(r)) - .toList(growable: false); + _suggestions = widget.initialSuggestions?.where((r) => !_chips.contains(r)).toList(growable: false); _suggestionsBoxController = SuggestionsBoxController(context); _effectiveFocusNode.addListener(_handleFocusChanged); @@ -183,19 +173,14 @@ class ChipsInputState extends State> final renderBoxOffset = renderBox!.localToGlobal(Offset.zero); final topAvailableSpace = renderBoxOffset.dy; final mq = MediaQuery.of(context); - final bottomAvailableSpace = mq.size.height - - mq.viewInsets.bottom - - renderBoxOffset.dy - - size.height; + final bottomAvailableSpace = mq.size.height - mq.viewInsets.bottom - renderBoxOffset.dy - size.height; var suggestionBoxHeight = max(topAvailableSpace, bottomAvailableSpace); if (null != widget.suggestionsBoxMaxHeight) { - suggestionBoxHeight = - min(suggestionBoxHeight, widget.suggestionsBoxMaxHeight!); + suggestionBoxHeight = min(suggestionBoxHeight, widget.suggestionsBoxMaxHeight!); } final showTop = topAvailableSpace > bottomAvailableSpace; // print("showTop: $showTop" ); - final compositedTransformFollowerOffset = - showTop ? Offset(0, -size.height) : Offset.zero; + final compositedTransformFollowerOffset = showTop ? Offset(0, -size.height) : Offset.zero; return StreamBuilder?>( stream: _suggestionsStreamController.stream, @@ -288,7 +273,7 @@ class ChipsInputState extends State> Future.delayed(const Duration(milliseconds: 300), () { WidgetsBinding.instance.addPostFrameCallback((_) async { final renderBox = context.findRenderObject() as RenderBox; - await Scrollable.of(context)?.position.ensureVisible(renderBox); + await Scrollable.of(context).position.ensureVisible(renderBox); }); }); } @@ -297,8 +282,7 @@ class ChipsInputState extends State> final localId = ++_searchId; final results = await widget.findSuggestions(value); if (_searchId == localId && mounted) { - setState(() => _suggestions = - results.where((r) => !_chips.contains(r)).toList(growable: false)); + setState(() => _suggestions = results.where((r) => !_chips.contains(r)).toList(growable: false)); } _suggestionsStreamController.add(_suggestions ?? []); if (!_suggestionsBoxController.isOpened && !_hasReachedMaxChips) { @@ -320,11 +304,9 @@ class ChipsInputState extends State> final oldTextEditingValue = _value; if (value.text != oldTextEditingValue.text) { setState(() => _value = value); - if (value.replacementCharactersCount < - oldTextEditingValue.replacementCharactersCount) { + if (value.replacementCharactersCount < oldTextEditingValue.replacementCharactersCount && _chips.isNotEmpty) { final removedChip = _chips.last; - setState(() => - _chips = Set.of(_chips.take(value.replacementCharactersCount))); + setState(() => _chips = Set.of(_chips.take(value.replacementCharactersCount))); widget.onChanged(_chips.toList(growable: false)); String? putText = ''; if (widget.allowChipEditing && _enteredTexts.containsKey(removedChip)) { @@ -332,8 +314,6 @@ class ChipsInputState extends State> _enteredTexts.remove(removedChip); } _updateTextInputState(putText: putText); - } else { - _updateTextInputState(); } _onSearchChanged(_value.normalCharactersText); } @@ -342,9 +322,7 @@ class ChipsInputState extends State> void _updateTextInputState({replaceText = false, putText = ''}) { if (replaceText || putText != '') { final updatedText = - String.fromCharCodes(_chips.map((_) => kObjectReplacementChar)) + - (replaceText ? '' : _value.normalCharactersText) + - putText; + String.fromCharCodes(_chips.map((_) => kObjectReplacementChar)) + (replaceText ? '' : _value.normalCharactersText) + putText; setState(() => _value = _value.copyWith( text: updatedText, selection: TextSelection.collapsed(offset: updatedText.length), @@ -355,6 +333,7 @@ class ChipsInputState extends State> _closeInputConnectionIfNeeded(); //Hack for #34 (https://github.com/danvick/flutter_chips_input/issues/34#issuecomment-684505282). TODO: Find permanent fix _textInputConnection ??= TextInput.attach(this, textInputConfiguration); _textInputConnection?.setEditingState(_value); + _textInputConnection?.show(); } @override @@ -412,12 +391,16 @@ class ChipsInputState extends State> @override AutofillScope? get currentAutofillScope => null; + @override + void performSelector(String selectorName) {} + + @override + void didChangeInputControl(TextInputControl? oldControl, TextInputControl? newControl) {} + @override Widget build(BuildContext context) { _nodeAttachment.reparent(); - final chipsChildren = _chips - .map((data) => widget.chipBuilder(context, this, data)) - .toList(); + final chipsChildren = _chips.map((data) => widget.chipBuilder(context, this, data)).toList(); final theme = Theme.of(context); @@ -434,8 +417,7 @@ class ChipsInputState extends State> _value.normalCharactersText, maxLines: 1, overflow: widget.textOverflow, - style: widget.textStyle ?? - theme.textTheme.subtitle1!.copyWith(height: 1.5), + style: widget.textStyle ?? theme.textTheme.titleMedium!.copyWith(height: 1.5), ), ), Flexible( @@ -447,38 +429,48 @@ class ChipsInputState extends State> ), ); - return NotificationListener( - onNotification: (SizeChangedLayoutNotification val) { - WidgetsBinding.instance.addPostFrameCallback((_) async { - _suggestionsBoxController.overlayEntry?.markNeedsBuild(); - }); - return true; + return RawKeyboardListener( + focusNode: _focusNode!, // or FocusNode() + onKey: (event) { + final str = currentTextEditingValue.text; + if (event.runtimeType.toString() == 'RawKeyDownEvent' && event.logicalKey == LogicalKeyboardKey.backspace && str.isNotEmpty) { + final sd = str.substring(0, str.length - 1); + updateEditingValue(TextEditingValue(text: sd, selection: TextSelection.collapsed(offset: sd.length))); + } }, - child: SizeChangedLayoutNotifier( - child: Column( - children: [ - GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - requestKeyboard(); - }, - child: InputDecorator( - decoration: widget.decoration, - isFocused: _effectiveFocusNode.hasFocus, - isEmpty: _value.text.isEmpty && _chips.isEmpty, - child: Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - spacing: 4.0, - runSpacing: 4.0, - children: chipsChildren, + child: NotificationListener( + onNotification: (SizeChangedLayoutNotification val) { + WidgetsBinding.instance.addPostFrameCallback((_) async { + _suggestionsBoxController.overlayEntry?.markNeedsBuild(); + }); + return true; + }, + child: SizeChangedLayoutNotifier( + child: Column( + children: [ + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + requestKeyboard(); + }, + child: InputDecorator( + decoration: widget.decoration, + isFocused: _effectiveFocusNode.hasFocus, + isEmpty: _value.text.isEmpty && _chips.isEmpty, + child: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 4.0, + runSpacing: 4.0, + children: chipsChildren, + ), ), ), - ), - CompositedTransformTarget( - link: _layerLink, - child: Container(), - ), - ], + CompositedTransformTarget( + link: _layerLink, + child: Container(), + ), + ], + ), ), ), ); diff --git a/lib/src/suggestions_box_controller.dart b/lib/src/suggestions_box_controller.dart index 127c7452..157d55eb 100644 --- a/lib/src/suggestions_box_controller.dart +++ b/lib/src/suggestions_box_controller.dart @@ -14,7 +14,7 @@ class SuggestionsBoxController { void open() { if (_isOpened) return; assert(overlayEntry != null); - Overlay.of(context)!.insert(overlayEntry!); + Overlay.of(context).insert(overlayEntry!); _isOpened = true; } diff --git a/lib/src/text_cursor.dart b/lib/src/text_cursor.dart index e00da661..e8a69d9f 100644 --- a/lib/src/text_cursor.dart +++ b/lib/src/text_cursor.dart @@ -13,11 +13,10 @@ class TextCursor extends StatefulWidget { final bool resumed; @override - _TextCursorState createState() => _TextCursorState(); + State createState() => _TextCursorState(); } -class _TextCursorState extends State - with SingleTickerProviderStateMixin { +class _TextCursorState extends State with SingleTickerProviderStateMixin { bool _displayed = false; late Timer _timer; @@ -46,9 +45,7 @@ class _TextCursorState extends State opacity: _displayed && widget.resumed ? 1.0 : 0.0, child: Container( width: 2.0, - color: theme.textSelectionTheme.cursorColor ?? - theme.textSelectionTheme.selectionColor ?? - theme.primaryColor, + color: theme.textSelectionTheme.cursorColor ?? theme.textSelectionTheme.selectionColor ?? theme.primaryColor, ), ), ); From d58c1d1d800086a450527135aa2ad69476bf0041 Mon Sep 17 00:00:00 2001 From: Eimji Date: Sun, 26 Feb 2023 11:19:44 +0100 Subject: [PATCH 2/2] Use WITH the mixin TextInputClient to avoid missing @override impls --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 2 ++ lib/.DS_Store | Bin 6148 -> 0 bytes lib/src/.DS_Store | Bin 6148 -> 0 bytes lib/src/chips_input.dart | 8 +------- 5 files changed, 3 insertions(+), 7 deletions(-) delete mode 100644 .DS_Store delete mode 100644 lib/.DS_Store delete mode 100644 lib/src/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 64e3d040bba1f41d084f6f59f986db6ed7478f77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKTZ_{`6h6~No7xrn;DSB~0bfhq7FQR1slA{JUSPB6gGx;{!3}0Jp-HV$3VGN6 zB0l;<^uPF|-&_`&wEHB8$eeQKo6Grfk}s2)4iT~8Jm?X%iO7Zvw637oVq#qQhShXW z3&`X(K2k;zd`f&H+H@ENi~|3f0^-}Cfg!uwg_H7KMHGDC{H2+Ps9UO7u0F%kKd zs4v^2{6&`PJO1XUag^nIdp}sMZe65AEF#~Q zX;A-KVOW@QA@bzqJ7PC0acCO*a|QHtv&9-<%qUSk!4w_+j*c5>EEFm_F@5-8Iy2KJ6ehFd`i=}I zHc)6vqkvJMtUz5g+hYHpTzvj7lT6DfU=;YT6kyia9S`wHdT-r$II-6{@HcQ_BCb#< lDJb-IEGuFwz7Cg$F-KH@1C513^uWv?0V#tii~@gEf!|FOz=Hq) diff --git a/.gitignore b/.gitignore index ed90a429..b4255e56 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,5 @@ pubspec.lock # Old files *.old + +.DS_Store diff --git a/lib/.DS_Store b/lib/.DS_Store deleted file mode 100644 index 142ba3fcc18feda70f5903f712dd6e686eab648c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKO>fgc5S>i|byOkc08+WF)N53dh(aYUCX_?3xPk+qV8?-47;j`dtu;{ADz!3UirJ0gG#oD5V(lTc71-n&c)yF8?^+ zpo42Ku-nKhY5H5#bJQHUAXqn1$+DXJw!SCxJge%#;D>6pJ9qBx1$)7M@IJaQ%czd) zMKzAgxBPZ)OrC7)IC-7TmXqH77pAD=teBNHAxmcndG{tOQnMVJMUhrEH*yt0H|S1! z4_B+vlc#+>8Xd3udNmxLJnrk`;mLa44IUgmdiHAaIsa0aOWR>m_{pu@^SFU47=F-S zqq4|N@d=(y^d?GB7!U@8ft_K%FHph$&h$t+A`A!vyTSmk4;soCdTbopr2~b%0s#3K zX$3YP2{}i53_UguQ3Fvf73flxzhWqt4!`zsp~uFdODE+oAIg7O`5TI|Uq}1ehLZ{% zN+}Eo1GgDyyVoA?|1bZ3|G%9iZ^D2u@Lw^YI;YX;7(?=V>(=0Suhq~GP!^7B9NwhB iuv;-=c`H7ET7h4)0SrAh4&i~wLBP@=g)s0>8Tbj5nrR^b diff --git a/lib/src/.DS_Store b/lib/src/.DS_Store deleted file mode 100644 index 8211f3b3e483e2011130ee350c2a1be61d016c62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKu};H441IzO(Uojk%}e~V?K+&gJ+*XZAn*zkR9DU z=gxk)JSlfE0Gaj6E1&={Wm6P&MofoCr;a@Mm?*}v!97-Z!5aMt(O(?WwHK)H%yqA^ zz5WgtSmF_{=x&;}S~Ts#Vu4%Y<%b*nGv@Vp;#Je@$kb8;r$fB>5P$Ml z@gnwg@+S+2lo_KB1ww&c1+@016?*<(^OG4Z@+~B~P#_feuL{Uyem9@-?fh*0@t%6t wCbkDQHH{n8q0!&@3E++HBd0c*=ac%3D; extends StatefulWidget { ChipsInputState createState() => ChipsInputState(); } -class ChipsInputState extends State> implements TextInputClient { +class ChipsInputState extends State> with TextInputClient { Set _chips = {}; List? _suggestions; final StreamController?> _suggestionsStreamController = StreamController?>.broadcast(); @@ -391,12 +391,6 @@ class ChipsInputState extends State> implements TextInputClient @override AutofillScope? get currentAutofillScope => null; - @override - void performSelector(String selectorName) {} - - @override - void didChangeInputControl(TextInputControl? oldControl, TextInputControl? newControl) {} - @override Widget build(BuildContext context) { _nodeAttachment.reparent();