Skip to content

Conversation

@xster
Copy link
Member

@xster xster commented Jul 14, 2017

#11148

flutter_01

Refactored some text selection stuff from material to widget.

Not in this PR:

@xster xster requested a review from collinjackson July 14, 2017 03:07
@xster xster requested a review from cbracken July 14, 2017 03:07
Copy link
Contributor

@collinjackson collinjackson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a fair bit of code in an area that I'm not knowledgeable about so a second reviewer might be useful. Most of my comments are stylistic.

Can we test this?

final double pressedOpacity;

/// The radius of the rounded corners of the button when it has a background
/// color. Defaults to 8 logical pixels.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put the second sentence in a separate paragraph.

Perhaps this should be a BorderRadius instead of a double to make it more configurable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

borderRadius: const BorderRadius.all(const Radius.circular(8.0)),
borderRadius: widget.borderRadius == null
? null
: new BorderRadius.all(new Radius.circular(widget.borderRadius)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're going to do it this way, I think you can use the BorderRadius.circular constructor here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored


/// Manages a copy/paste text selection toolbar.
class _TextSelectionToolbar extends StatelessWidget {
const _TextSelectionToolbar(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though this widget is private, I would use named parameters here because you have several parameters of the same type.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


@override
bool shouldRepaint(_TextSelectionToolbarNotchPainter oldPainter) {
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible candidate for fat-arrow syntax

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

void paint(Canvas canvas, Size size) {
final Paint paint = new Paint()..color = _selectionToolbarBackgroundBlack;
final Path triangle = new Path();
triangle.lineTo(_selectionToolbarTriangleSize.width / 2, 0.0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use the .. cascade operator here and below.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nice. It's a lot cleaner. Thanks!

Size get handleSize;

void handleCut(TextSelectionDelegate delegate) {
Clipboard.setData(new ClipboardData(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You use delegate.textEditingValue here a lot, I think you should assign it to a local final.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

final ValueChanged<String> onSubmitted;

/// Optional input validation and formatting overrides. Formatters are run
/// Optional input validation and formatting overrides. Formatters are run
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You didn't introduce this, but since you touched this line, can you move the second sentence into its own paragraph?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

child: new Row(mainAxisSize: MainAxisSize.min, children: items),
),
// TODO(xster): position the triangle based on the layout delegate.
// And avoid letting the triangle line up with any dividers.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this get an issue as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


const Color _selectionToolbarBackgroundBlack = const Color(0xFF2E2E2E);
const Color _selectionToolbarDividerGray = const Color(0xFFB9B9B9);
const Color _selectionHandlesBlue = const Color(0xFF146DDE);
Copy link
Contributor

@collinjackson collinjackson Jul 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Having a description of the color in the name of color constants seems a bit odd to me. "Color" instead of "Black/Gray/Blue" would concentrate the knowledge of what these colors actually are to a single place instead of everywhere the constants are used.

You can see this in other places in Flutter, e.g. _kActiveTickColor, _kDisabledBackground

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// Padding around the line at the edge of the text selection that has 0 width and
// the height of the text font.
const double _selectionHandlesPadding = 18.0;
const double _kToolbarScreenPadding = 8.0; // pixels
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I found this comment a bit confusing since all padding is pixels and was wondering if it is trying to specify logical vs physical? I realized it's probably copy-pasted from previous code, but the comment isn't on the line above. May be better to remove it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaned up a bit here and it material

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like several of these arguments should be asserted-non-null and have a comment in the docs for the constructor that says they must not be null (see other widgets for examples of the style for these docs).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a few more null handling instead

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0.5 doesn't correspond to one physical pixel, does it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't it for ios?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iPhone 6 Plus has a device pixel ratio of 3. iPhone 3 has a device pixel ratio of 1. But also, all the iOS code has to work on Android devices and Fuchsia and whatever else.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double checked. It is indeed exactly one physical pixel on all devices. Changed from constant to read the device pixel ratio.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as written this will never match.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, sorry, missed some refactor cleanup

@xster xster force-pushed the platform-text-selection branch from 3b537ce to d30e07d Compare July 17, 2017 23:42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 -> 2.0 to avoid an int-to-double conversion

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what "Also flipped for iOS" means.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reworded a bit

@xster xster force-pushed the platform-text-selection branch from d30e07d to 19a277d Compare July 17, 2017 23:45
@xster xster force-pushed the platform-text-selection branch 2 times, most recently from 009556b to 42d2b09 Compare July 18, 2017 20:21
@xster xster force-pushed the platform-text-selection branch from 42d2b09 to 67a3037 Compare July 18, 2017 20:41
@collinjackson
Copy link
Contributor

Posse wanted to check if there's still work to be done here or if this can be merged.

@alardizabal

@xster
Copy link
Member Author

xster commented Jul 21, 2017

It's done, just waiting for an LGTM

@xster xster merged commit aa096b5 into flutter:master Jul 21, 2017
@xster xster deleted the platform-text-selection branch July 21, 2017 15:33
child: widget.selectionControls.buildHandle(
context,
type,
widget.renderObject.size.height / widget.renderObject.maxLines,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,
Seems this changes cause exception in case when TextField was created with unlimited lines new TextField(maxLines: null).
Steps:

  • Create TextField with maxLines = null
  • Enter some text, tap Done button
  • Tap on TextField again

200w_d

➜  mobileapp git:(develop) ✗ flutter --version

Flutter • channel master • https://github.com/flutter/flutter.git
Framework • revision a92a62706c (16 hours ago) • 2017-07-21 16:57:33 -0700
Engine • revision 5fcfb995bb
Tools • Dart 1.25.0-dev.7.0
The following NoSuchMethodError was thrown building _TextSelectionHandleOverlay(dirty; state:
_TextSelectionHandleOverlayState#201d1()):
The method 'toDouble' was called on null.
Receiver: null
Tried calling: toDouble()

When the exception was thrown, this was the stack:
#0      Object._noSuchMethod (dart:core-patch/object_patch.dart:42)
#1      Object.noSuchMethod (dart:core-patch/object_patch.dart:46)
#2      double./ (dart:core-patch/double.dart:39)
#3      _TextSelectionHandleOverlayState.build (package:flutter/src/widgets/text_selection.dart:482:49)
#4      StatefulElement.build (package:flutter/src/widgets/framework.dart:3632:27)
#5      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3542:15)
#6      Element.rebuild (package:flutter/src/widgets/framework.dart:3443:5)
#7      ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3522:5)
#8      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3660:22)
#9      ComponentElement.mount (package:flutter/src/widgets/framework.dart:3517:5)
#10     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2901:14)
#11     Element.updateChild (package:flutter/src/widgets/framework.dart:2704:12)
#12     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4526:14)
#13     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2901:14)
#14     Element.updateChild (package:flutter/src/widgets/framework.dart:2704:12)
#15     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3554:16)
#16     Element.rebuild (package:flutter/src/widgets/framework.dart:3443:5)
#17     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3522:5)
#18     StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3660:22)
#19     ComponentElement.mount (package:flutter/src/widgets/framework.dart:3517:5)
#20     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2901:14)
#21     Element.updateChild (package:flutter/src/widgets/framework.dart:2704:12)
#22     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3554:16)
#23     Element.rebuild (package:flutter/src/widgets/framework.dart:3443:5)
#24     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3522:5)
#25     StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3660:22)
#26     ComponentElement.mount (package:flutter/src/widgets/framework.dart:3517:5)
#27     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2901:14)
#28     Element.updateChild (package:flutter/src/widgets/framework.dart:2704:12)
#29     RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4317:32)
#30     MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4641:17)
#31     Element.updateChild (package:flutter/src/widgets/framework.dart:2693:15)
#32     _TheatreElement.update (package:flutter/src/widgets/overlay.dart:505:16)
#33     Element.updateChild (package:flutter/src/widgets/framework.dart:2693:15)
#34     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3554:16)
#35     Element.rebuild (package:flutter/src/widgets/framework.dart:3443:5)
#36     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2279:33)
#37     BindingBase&SchedulerBinding&GestureBinding&ServicesBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:503:20)
#38     BindingBase&SchedulerBinding&GestureBinding&ServicesBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:189:5)
#39     BindingBase&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:688:15)
#40     BindingBase&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:636:9)
#41     _invoke (file:///Users/herman/Projects/github/flutter/bin/cache/pkg/sky_engine/lib/ui/hooks.dart:86)
#42     _drawFrame (file:///Users/herman/Projects/github/flutter/bin/cache/pkg/sky_engine/lib/ui/hooks.dart:75)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for tracking this down. Got a patch in #11353

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 13, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants