-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Make _SelectableRegionSelectionContainerDelegate public
#147080
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make _SelectableRegionSelectionContainerDelegate public
#147080
Conversation
|
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact "@test-exemption-reviewer" in the #hackers channel in Chat (don't just cc them here, they won't see it! Use Discord!). If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
a365067 to
32aa4fd
Compare
|
Friendly bump for review. Also if this needs more tests let me know, I can add them (maybe a separate test file?) but initially didn't because the functionality of the delegate is verified in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably start with something like
A delegate that manages ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why would this become public? I think the synthesize selection events logic is implementation details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah this is for subclass to implement their selection logic. It would be good if we can provide some sort of low level selection API, for example
void updateInternalStateBeforeAndAfterSelection(child, callback) {
ensureChildUpdated(child);
callback();
_hasReceivedStartEvent.add(child);
_hasReceivedEndEvent.add(child);
}and then subclass can do
SelectionResult handleSelectParagraph(event) {
for(..) {
updateInternalStateBeforeAndAfterSelection(selectable,() {_handleSelectParagraph} )
}
}If we can't completely hide these internal state, at least make them readonly, so that only one class is updating the state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think i missed this, why do we need to duplicate these two method in this class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did this to handle the behavior where to keep the origin boundary within the selection we swap the selection edges when they invert. We didn't need this for word boundary because a word boundary is guaranteed to be within one _SelectableFragment, but with paragraphs the origin boundary may span multiple _SelectableFragments so I needed to account for these swaps at the container level so it has an accurate currentSelectionStartIndex and currentSelectionEndIndex.
962befb to
24f25a2
Compare
justinmc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍 but maybe @chunhtai should also give a final sign off. Sorry for the slow review!
|
|
||
| class _SelectableRegionContainerDelegate extends MultiSelectableSelectionContainerDelegate { | ||
| /// A delegate that manages updating multiple [Selectable] children where the | ||
| /// [Selectable]s do not change or move around frequently. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Maybe point people towards MultiSelectableSelectionContainerDelegate for cases that DO move around? If that's not already obvious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this nowadays, not sure if I understood correctly but there is a reference to MultiSelectableSelectionContainerDelegate in the "See also" so seems good now.
| return super.dispatchSelectionEventToChild(selectable, event); | ||
| } | ||
|
|
||
| /// Ensures the [Selectable] child has received up to date selection event. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: "event" => "events"? Or "the most up to date selection event"?
| /// Copies the selected contents of all [Selectable]s, separating their | ||
| /// contents with a new line. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh was this PR prompted by the issue about putting a newline between copied widgets?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and anyone trying to use SelectionContainer has to re-implement or copy and paste a lot of this logic since it requires a SelectionContainerDelegate.
| child: SelectionContainer( | ||
| delegate: selectionDelegate, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be done near the top of the widget tree for a big app with a single SelectionContainer, so that nearly everything has this newline behavior? Or would you need to do a bunch of SelectionContainers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would still need multiple SelectionContainers because getSelectedContent does not propagate down the tree.
|
Hi @Renzo-Olivares, are you still planning on coming back to this pr? |
|
@chunhtai I plan to come back to this soon. |
6df88be to
0ff440c
Compare
49e7b41 to
61c1da3
Compare
| /// This method is called when: | ||
| /// 1. A new [Selectable] is added to the delegate, and its screen location | ||
| /// falls into the previous selection. | ||
| /// 2. A [Selectable] is dispatched a [SelectionEvent] of type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before a [SelectionEvent] is dispatched to a [Selectable]
| /// When `forEnd` is null, the [Selectable] will be registered as having received both | ||
| /// start and end events. | ||
| @protected | ||
| void trackInternalSelectionStateForSelectable({required Selectable selectable, bool? forEnd}) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The naming for these method should be describing what condition will trigger this method instead of describing what the internal logic does. Something like
didReceiveSelectionEdgeEventFor();.
The current name may not make sense after several level of subclassing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe handleSelectionEdgeEventFor? I always look at this in the style guide but not sure if it applies here: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md#naming-rules-for-typedefs-and-function-variables
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think handle* may be confusing since we already have methods like handleSelectWord, and handleSelectionEdgeUpdate. didReceive makes a good distinction since these methods are only tracking the events and not actually doing any of the logic that moves a selection edge.
| /// When `forEnd` is true, the [Selectable] will be registered as having received | ||
| /// an end event. When false, the [Selectable] is registered as having received | ||
| /// a start event. | ||
| /// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also mention in what condition subclass may want to override/calling this method?
| /// and [currentSelectionEndIndex] should be set to valid values at the time | ||
| /// this method is called. | ||
| @protected | ||
| void updateInternalSelectionStateForBoundaryEvents() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same, this should probably named didReceiveSelectionBoundaryEvents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same for other methods
| /// This indicates that the given `selectable` has neither received a | ||
| /// start or end [SelectionEdgeUpdateEvent]s. | ||
| @protected | ||
| void clearInternalSelectionStateForSelectable(Selectable selectable) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there any subclass that uses this method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not at the moment, but it is used by public methods like remove and dispatchSelectionEventToChild, so I think if someone extends this delegate they may want access to this method.
justinmc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM but I'm still deferring to @chunhtai for final approval.
Does this PR also solve the problem of #146625?
Also just a general question about SelectionContainer, probably unrelated to this PR. Can I just stick the SelectionContainer directly under the SelectableRegion if I want to affect everything that it makes selectable? Just thinking that that's probably how most people will use this.
| final LayerLink _endHandleLayerLink = LayerLink(); | ||
| final LayerLink _toolbarLayerLink = LayerLink(); | ||
| final _SelectableRegionContainerDelegate _selectionDelegate = _SelectableRegionContainerDelegate(); | ||
| final MultiStaticSelectableSelectionContainerDelegate _selectionDelegate = MultiStaticSelectableSelectionContainerDelegate(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wanted to check if this name would be any better if it was shorter. Maybe MultiStaticSelectableDelegate or StaticSelectablesSelectionContainerDelegate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to StaticSelectionContainerDelegate, open to other suggestions. We have a private _ScrollableSelectionContainerDelegate, so I think this name makes sense given that convention.
|
|
||
| class _SelectableRegionContainerDelegate extends MultiSelectableSelectionContainerDelegate { | ||
| /// A delegate that manages updating multiple [Selectable] children where the | ||
| /// [Selectable]s do not change or move around frequently. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this nowadays, not sure if I understood correctly but there is a reference to MultiSelectableSelectionContainerDelegate in the "See also" so seems good now.
| /// When `forEnd` is null, the [Selectable] will be registered as having received both | ||
| /// start and end events. | ||
| @protected | ||
| void trackInternalSelectionStateForSelectable({required Selectable selectable, bool? forEnd}) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe handleSelectionEdgeEventFor? I always look at this in the style guide but not sure if it applies here: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md#naming-rules-for-typedefs-and-function-variables
| child: Center( | ||
| child: SelectionContainer( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super nit: I wonder if it's better to put the SelectionContainer above the Center? I'm guessing most people will use this to cover everything under as single SelectableRegion. Or is there any benefit to keeping this as-is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense to me, updated.
|
This pull request executed golden file tests, but it has not been updated in a while (20+ days). Test results from Gold expire after as many days, so this pull request will need to be updated with a fresh commit in order to get results from Gold. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
|
(PR triage): What is the status if this PR? :) |
8c3c351 to
4c71b37
Compare
justinmc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renewing my LGTM 👍
| if (forEnd == null) { | ||
| _hasReceivedStartEvent.add(selectable); | ||
| _hasReceivedEndEvent.add(selectable); | ||
| return; | ||
| } | ||
| if (forEnd) { | ||
| _hasReceivedEndEvent.add(selectable); | ||
| } else { | ||
| _hasReceivedStartEvent.add(selectable); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Maybe a switch on forEnd?
chunhtai
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, except for the comments
| /// locations for start and end [SelectionEdgeUpdateEvent]s. | ||
| @protected | ||
| void clearInternalSelectionState() { | ||
| _hasReceivedStartEvent.clear(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we expose clearInternalSelectionStateForSelectable, this should be a for loop to call clearInternalSelectionStateForSelectable
| /// This indicates that the given `selectable` has neither received a | ||
| /// start or end [SelectionEdgeUpdateEvent]s. | ||
| @protected | ||
| void clearInternalSelectionStateForSelectable(Selectable selectable) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the doc should mention sub class should clean up state they added in didReceive- method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same for the didReceive method that state should be clean up in this method
d2ac9fb to
1dae4ff
Compare
flutter/flutter@73546b3...c8510f2 2024-11-08 [email protected] Roll Flutter Engine from 44d788f4651b to a08bd5a07c2a (3 revisions) (flutter/flutter#158375) 2024-11-08 [email protected] Add ability to override `NavigationDestination.label` padding for `NavigationBar` (flutter/flutter#158260) 2024-11-08 [email protected] Add flutter/package code generation instructions (flutter/flutter#158326) 2024-11-08 [email protected] Roll Flutter Engine from 8e19915c19fc to 44d788f4651b (3 revisions) (flutter/flutter#158362) 2024-11-08 [email protected] Roll Flutter Engine from bcb281cde579 to 8e19915c19fc (4 revisions) (flutter/flutter#158354) 2024-11-07 [email protected] Make `_SelectableRegionSelectionContainerDelegate` public (flutter/flutter#147080) 2024-11-07 [email protected] Manual roll Flutter Engine from 371c86fb6b49 to bcb281cde579 (flutter/flutter#158346) 2024-11-07 [email protected] Add clarification on review timelines in PR template (flutter/flutter#158345) 2024-11-07 [email protected] Increase Java heap limit to 8GB for plugin integration tests using deferred components (flutter/flutter#158330) 2024-11-07 [email protected] Roll pub packages (flutter/flutter#158337) 2024-11-07 [email protected] Roll Flutter Engine from ac50b20ae5c9 to 371c86fb6b49 (5 revisions) (flutter/flutter#158336) 2024-11-07 [email protected] Fix a breakage caused by the test being unskipped. (flutter/flutter#158335) 2024-11-07 [email protected] Roll Flutter Engine from 8a963cfc134c to ac50b20ae5c9 (1 revision) (flutter/flutter#158308) 2024-11-07 [email protected] `Plugin.isDevDependency` if exclusively in `dev_dependencies` (flutter/flutter#157462) 2024-11-07 [email protected] Add recently imported packages to issue template (flutter/flutter#158324) 2024-11-07 [email protected] Roll Flutter Engine from 076688d95818 to 8a963cfc134c (1 revision) (flutter/flutter#158304) 2024-11-07 [email protected] Roll Flutter Engine from 94dac953a95f to 076688d95818 (2 revisions) (flutter/flutter#158303) 2024-11-07 [email protected] Make leak tracking bots blocking. (flutter/flutter#157866) 2024-11-07 [email protected] Roll Flutter Engine from b36ca3319825 to 94dac953a95f (1 revision) (flutter/flutter#158297) 2024-11-06 [email protected] Roll Flutter Engine from 58ac1dadd69d to b36ca3319825 (9 revisions) (flutter/flutter#158295) 2024-11-06 [email protected] Added cusor control properties to CupertinoSearchTextField and tests (flutter/flutter#158240) 2024-11-06 [email protected] Fix flakiness in hot_reload_test.dart (flutter/flutter#158271) 2024-11-06 [email protected] Fix use of deprecated `buildDir` in Android templates/tests/examples (flutter/flutter#157560) 2024-11-06 [email protected] Roll Flutter Engine from f03f11300a9d to 58ac1dadd69d (5 revisions) (flutter/flutter#158283) 2024-11-06 [email protected] Roll pub packages (flutter/flutter#158281) 2024-11-06 [email protected] Delete firebase_android_embedding_v2_smoke_test (flutter/flutter#158223) 2024-11-06 [email protected] [web] fix --ab option for web benchmarks (flutter/flutter#154574) 2024-11-06 [email protected] excluding website-cms from critical pr triage (flutter/flutter#158220) 2024-11-06 [email protected] Add test for `image.frame_builder.0.dart` (flutter/flutter#158247) 2024-11-06 [email protected] Roll Packages from 7219431 to bb5a258 (6 revisions) (flutter/flutter#158267) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
This change makes
_SelectableRegionContainerDelegatepublic so it can be reused and extended by users ofSelectionContainer. ExtendingMultiSelectableRegionContainerDelegatedoes not by default provide selection managing across multiple selectables, so often users will copy the implementation found in_SelectableRegionContainerDelegate._SelectableRegionContainerDelegate->StaticSelectionContainerDelegate.Pre-launch Checklist
///).