Updating checkbox to handle tap (#186)

* updating checkbox to handle tap

* updating checkbox to handle long press and using UniqueKey() to avoid weird side effects

* removed useless doc

Co-authored-by: Kevin Despoulains <kevin.despoulains@scriptandgo.com>
pull/205/head^2
kevinDespoulains 4 years ago committed by GitHub
parent da2a05aaa0
commit e49421f48c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 32
      lib/widgets/editor.dart
  2. 44
      lib/widgets/raw_editor.dart
  3. 70
      lib/widgets/text_block.dart

@ -393,8 +393,6 @@ class _QuillEditorSelectionGestureDetectorBuilder
final segmentResult = line.queryChild(result.offset, false);
if (segmentResult.node == null) {
if (line.length == 1) {
// tapping when no text yet on this line
_flipListCheckbox(pos, line, segmentResult);
getEditor()!.widget.controller.updateSelection(
TextSelection.collapsed(offset: pos.offset), ChangeSource.LOCAL);
return true;
@ -434,37 +432,9 @@ class _QuillEditorSelectionGestureDetectorBuilder
),
);
}
return false;
}
if (_flipListCheckbox(pos, line, segmentResult)) {
return true;
}
return false;
}
bool _flipListCheckbox(
TextPosition pos, Line line, container_node.ChildQuery segmentResult) {
if (getEditor()!.widget.readOnly ||
!line.style.containsKey(Attribute.list.key) ||
segmentResult.offset != 0) {
return false;
}
// segmentResult.offset == 0 means tap at the beginning of the TextLine
final String? listVal = line.style.attributes[Attribute.list.key]!.value;
if (listVal == Attribute.unchecked.value) {
getEditor()!
.widget
.controller
.formatText(pos.offset, 0, Attribute.checked);
} else if (listVal == Attribute.checked.value) {
getEditor()!
.widget
.controller
.formatText(pos.offset, 0, Attribute.unchecked);
}
getEditor()!.widget.controller.updateSelection(
TextSelection.collapsed(offset: pos.offset), ChangeSource.LOCAL);
return true;
return false;
}
Future<void> _launchUrl(String url) async {

@ -579,6 +579,18 @@ class RawEditorState extends EditorState
}
}
/// Updates the checkbox positioned at [offset] in document
/// by changing its attribute according to [value].
void _handleCheckboxTap(int offset, bool value) {
if (!widget.readOnly) {
if (value) {
widget.controller.formatText(offset, 0, Attribute.checked);
} else {
widget.controller.formatText(offset, 0, Attribute.unchecked);
}
}
}
List<Widget> _buildChildren(Document doc, BuildContext context) {
final result = <Widget>[];
final indentLevelCounts = <int, int>{};
@ -589,21 +601,23 @@ class RawEditorState extends EditorState
} else if (node is Block) {
final attrs = node.style.attributes;
final editableTextBlock = EditableTextBlock(
node,
_textDirection,
widget.scrollBottomInset,
_getVerticalSpacingForBlock(node, _styles),
widget.controller.selection,
widget.selectionColor,
_styles,
widget.enableInteractiveSelection,
_hasFocus,
attrs.containsKey(Attribute.codeBlock.key)
? const EdgeInsets.all(16)
: null,
widget.embedBuilder,
_cursorCont,
indentLevelCounts);
node,
_textDirection,
widget.scrollBottomInset,
_getVerticalSpacingForBlock(node, _styles),
widget.controller.selection,
widget.selectionColor,
_styles,
widget.enableInteractiveSelection,
_hasFocus,
attrs.containsKey(Attribute.codeBlock.key)
? const EdgeInsets.all(16)
: null,
widget.embedBuilder,
_cursorCont,
indentLevelCounts,
_handleCheckboxTap,
);
result.add(editableTextBlock);
} else {
throw StateError('Unreachable.');

@ -61,6 +61,7 @@ class EditableTextBlock extends StatelessWidget {
this.embedBuilder,
this.cursorCont,
this.indentLevelCounts,
this.onCheckboxTap,
);
final Block block;
@ -76,6 +77,7 @@ class EditableTextBlock extends StatelessWidget {
final EmbedBuilder embedBuilder;
final CursorCont cursorCont;
final Map<int, int> indentLevelCounts;
final Function(int, bool) onCheckboxTap;
@override
Widget build(BuildContext context) {
@ -161,12 +163,23 @@ class EditableTextBlock extends StatelessWidget {
if (attrs[Attribute.list.key] == Attribute.checked) {
return _Checkbox(
style: defaultStyles!.leading!.style, width: 32, isChecked: true);
key: UniqueKey(),
style: defaultStyles!.leading!.style,
width: 32,
isChecked: true,
offset: block.offset + line.offset,
onTap: onCheckboxTap,
);
}
if (attrs[Attribute.list.key] == Attribute.unchecked) {
return _Checkbox(
style: defaultStyles!.leading!.style, width: 32, isChecked: false);
key: UniqueKey(),
style: defaultStyles!.leading!.style,
width: 32,
offset: block.offset + line.offset,
onTap: onCheckboxTap,
);
}
if (attrs.containsKey(Attribute.codeBlock.key)) {
@ -685,46 +698,39 @@ class _BulletPoint extends StatelessWidget {
}
}
class _Checkbox extends StatefulWidget {
const _Checkbox({Key? key, this.style, this.width, this.isChecked})
: super(key: key);
class _Checkbox extends StatelessWidget {
const _Checkbox({
Key? key,
this.style,
this.width,
this.isChecked = false,
this.offset,
this.onTap,
}) : super(key: key);
final TextStyle? style;
final double? width;
final bool? isChecked;
final bool isChecked;
final int? offset;
final Function(int, bool)? onTap;
@override
__CheckboxState createState() => __CheckboxState();
}
class __CheckboxState extends State<_Checkbox> {
bool? isChecked;
void _onCheckboxClicked(bool? newValue) => setState(() {
isChecked = newValue;
if (isChecked!) {
// check list
} else {
// uncheck list
}
});
@override
void initState() {
super.initState();
isChecked = widget.isChecked;
void _onCheckboxClicked(bool? newValue) {
if (onTap != null && newValue != null && offset != null) {
onTap!(offset!, newValue);
}
}
@override
Widget build(BuildContext context) {
return Container(
alignment: AlignmentDirectional.topEnd,
width: widget.width,
width: width,
padding: const EdgeInsetsDirectional.only(end: 13),
child: Checkbox(
value: widget.isChecked,
onChanged: _onCheckboxClicked,
child: GestureDetector(
onLongPress: () => _onCheckboxClicked(!isChecked),
child: Checkbox(
value: isChecked,
onChanged: _onCheckboxClicked,
),
),
);
}

Loading…
Cancel
Save