diff --git a/lib/src/widgets/toolbar/search_dialog.dart b/lib/src/widgets/toolbar/search_dialog.dart index b8ce67ac..08babac1 100644 --- a/lib/src/widgets/toolbar/search_dialog.dart +++ b/lib/src/widgets/toolbar/search_dialog.dart @@ -23,6 +23,8 @@ class _SearchDialogState extends State { late TextEditingController _controller; late List? _offsets; late int _index; + bool _case_sensitive = false; + bool _whole_word = false; @override void initState() { @@ -35,87 +37,113 @@ class _SearchDialogState extends State { @override Widget build(BuildContext context) { - return StatefulBuilder(builder: (context, setState) { - var label = ''; - if (_offsets != null) { - label = '${_offsets!.length} ${'matches'.i18n}'; - if (_offsets!.isNotEmpty) { - label += ', ${'showing match'.i18n} ${_index + 1}'; - } + var matchShown = ''; + if (_offsets != null) { + if (_offsets!.isEmpty) { + matchShown = '0/0'; + } else { + matchShown = '${_index + 1}/${_offsets!.length}'; } - return AlertDialog( - backgroundColor: widget.dialogTheme?.dialogBackgroundColor, - content: Container( - height: 100, - child: Column( - children: [ - TextField( - keyboardType: TextInputType.multiline, - style: widget.dialogTheme?.inputTextStyle, - decoration: InputDecoration( - labelText: 'Search'.i18n, - labelStyle: widget.dialogTheme?.labelTextStyle, - floatingLabelStyle: widget.dialogTheme?.labelTextStyle), - autofocus: true, - onChanged: _textChanged, - controller: _controller, + } + + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5), + ), + backgroundColor: widget.dialogTheme?.dialogBackgroundColor, + alignment: Alignment.bottomCenter, + insetPadding: EdgeInsets.zero, + child: SizedBox( + height: 45, + child: Row( + children: [ + Tooltip( + message: 'Case sensitivity and whole word search', + child: ToggleButtons( + onPressed: (int index) { + if (index == 0) { + _changeCaseSensitivity(); + } else if (index == 1) { + _changeWholeWord(); + } + }, + borderRadius: const BorderRadius.all(Radius.circular(2)), + isSelected: [_case_sensitive, _whole_word], + children: const [ + Text( + '\u0391\u03b1', + style: TextStyle( + fontFamily: 'MaterialIcons', + fontSize: 24, + ), + ), + Text( + '\u201c\u2026\u201d', + style: TextStyle( + fontFamily: 'MaterialIcons', + fontSize: 24, + ), + ), + ], ), - if (_offsets != null) - Padding( - padding: const EdgeInsets.all(8), - child: Text(label, textAlign: TextAlign.left), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(bottom: 12, left: 5), + child: TextField( + style: widget.dialogTheme?.inputTextStyle, + decoration: InputDecoration( + isDense: true, + suffixText: (_offsets != null) ? matchShown : '', + suffixStyle: widget.dialogTheme?.labelTextStyle, + ), + autofocus: true, + onChanged: _textChanged, + textInputAction: TextInputAction.done, + onEditingComplete: _findText, + controller: _controller, ), - ], - ), - ), - actions: [ - if (_offsets != null && _offsets!.isNotEmpty && _index > 0) - TextButton( - onPressed: () { - setState(() { - _index -= 1; - }); - _moveToPosition(); - }, - child: Text( - 'Prev'.i18n, - style: widget.dialogTheme?.labelTextStyle, ), ), - if (_offsets != null && - _offsets!.isNotEmpty && - _index < _offsets!.length - 1) - TextButton( - onPressed: () { - setState(() { - _index += 1; - }); - _moveToPosition(); - }, - child: Text( - 'Next'.i18n, - style: widget.dialogTheme?.labelTextStyle, + if (_offsets == null) + IconButton( + icon: const Icon(Icons.search), + tooltip: 'Find text', + onPressed: _findText, ), - ), - if (_offsets == null && _text.isNotEmpty) - TextButton( - onPressed: () { - setState(() { - _offsets = widget.controller.document.search(_text); - _index = 0; - }); - if (_offsets!.isNotEmpty) { - _moveToPosition(); - } - }, - child: Text( - 'Ok'.i18n, - style: widget.dialogTheme?.labelTextStyle, + if (_offsets != null) + IconButton( + icon: const Icon(Icons.keyboard_arrow_up), + tooltip: 'Move to previous occurrence', + onPressed: (_offsets!.isNotEmpty) ? _moveToPrevious : null, ), - ), - ], + if (_offsets != null) + IconButton( + icon: const Icon(Icons.keyboard_arrow_down), + tooltip: 'Move to next occurrence', + onPressed: (_offsets!.isNotEmpty) ? _moveToNext : null, + ), + ], + ), + ), + ); + } + + void _findText() { + if (_text.isEmpty) { + return; + } + setState(() { + _offsets = widget.controller.document.search( + _text, + caseSensitive: _case_sensitive, + wholeWord: _whole_word, ); + _index = 0; }); + if (_offsets!.isNotEmpty) { + _moveToPosition(); + } } void _moveToPosition() { @@ -126,6 +154,34 @@ class _SearchDialogState extends State { ChangeSource.LOCAL); } + void _moveToPrevious() { + if (_offsets!.isEmpty) { + return; + } + setState(() { + if (_index > 0) { + _index -= 1; + } else { + _index = _offsets!.length - 1; + } + }); + _moveToPosition(); + } + + void _moveToNext() { + if (_offsets!.isEmpty) { + return; + } + setState(() { + if (_index < _offsets!.length - 1) { + _index += 1; + } else { + _index = 0; + } + }); + _moveToPosition(); + } + void _textChanged(String value) { setState(() { _text = value; @@ -133,4 +189,20 @@ class _SearchDialogState extends State { _index = 0; }); } + + void _changeCaseSensitivity() { + setState(() { + _case_sensitive = !_case_sensitive; + _offsets = null; + _index = 0; + }); + } + + void _changeWholeWord() { + setState(() { + _whole_word = !_whole_word; + _offsets = null; + _index = 0; + }); + } }