-
Notifications
You must be signed in to change notification settings - Fork 29.1k
Initial implementation of AnnotatedRegion for system chrome #17672
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
Conversation
@@ -184,6 +186,14 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> | |||
} | |||
} | |||
|
|||
void _updateSystemChrome() { | |||
final SystemUiOverlayStyle overlayStyle = layer.findRegion( | |||
Offset.zero, |
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 suggestion I had was for when we just had one colour for everything. Now that we have two colours (at least), we probably want to independently get the details for the top and the bottom.
For the top, I'd probably aim for a point half way across the width, and half of the way down the top padding.
Similarly for the other sources.
_latestStyle = _pendingStyle; | ||
} | ||
_pendingStyle = null; | ||
}); |
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.
we might want to keep the old behaviour around in case anyone else wants to use this API, and doesn't have a way to guarantee they only call it once per frame.
} | ||
|
||
/// Render object for the [AnnotatedRegion]. | ||
class AnnotatedRegionRenderObject<T> extends RenderProxyBox { |
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.
shouldn't this be in proxy_box?
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 render_object, or the whole annotated_region API?
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 render object.
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.
Moved
This looks fantastic.
not sure what you mean by "proper"? This seems pretty good already.
We could have a default. I'd be tempted to just say if there's no information, we don't change it. I would recommend adding more tests, e.g. to check if it works with crazy layer types like the leader/follower layers, if it works with scrolling of slivers, etc. |
When you fix whatever angered the bots, please see if you can also fix the _verifyNoBadImportsInFlutter logic to not crash when handling whatever you did... thanks :-) |
examples/hello_world/lib/main.dart
Outdated
import 'package:flutter/widgets.dart'; | ||
|
||
void main() => runApp(const Center(child: const Text('Hello, world!', textDirection: TextDirection.ltr))); |
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.
Please don't change the hello world example. The whole point of this example is to be a one liner.
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.
Sorry commited by mistake, was using this to debug values - will revert
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.
Fixed
@@ -536,7 +536,10 @@ class OffsetLayer extends ContainerLayer { | |||
|
|||
@override | |||
Object findRegion(Offset offset, Type type) { | |||
return super.findRegion(offset + this.offset, 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.
Please name the argument something that doesn't shadow a member variable.
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.
Fixed
@@ -536,7 +536,10 @@ class OffsetLayer extends ContainerLayer { | |||
|
|||
@override | |||
Object findRegion(Offset offset, Type type) { | |||
return super.findRegion(offset + this.offset, type); | |||
if (offset <= this.offset) { |
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?
systemNavigationBarDividerColor: lowerOverlayStyle.systemNavigationBarDividerColor, | ||
)); | ||
} else if (upperOverlayStyle != null || lowerOverlayStyle != null) { | ||
SystemChrome.setSystemUIOverlayStyle(upperOverlayStyle ?? lowerOverlayStyle); |
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 seems weird that when an upper overlay style goes out of view, suddenly the lower overlay style controls the top system ui overlay.
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.
Fixed
S find<S>(Offset regionOffset) { | ||
if (_invertedTransform == null) { | ||
_invertedTransform ??= new Matrix4.zero(); | ||
_transform?.copyInto(_invertedTransform)?.invert(); |
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.
there's a method or constructor or something that'll get you a new matrix that represents the inverse of another, which'll save you having to manually create the new one.
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.
Fixed
@override | ||
S find<S>(Offset regionOffset) { | ||
final Offset transformed = regionOffset - offset; | ||
return super.find<S>(transformed); |
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 don't mind which we do, but we should be consistent in the style between this one and LeaderLayer's.
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.
Fixed
} | ||
final Vector4 vector = new Vector4(regionOffset.dx, regionOffset.dy, 0.0, 1.0); | ||
final Vector4 result = _invertedTransform.transform(vector); | ||
return super.find<S>(new Offset(result[0] - linkedOffset.dx, result[1] - linkedOffset.dy)); |
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 doesn't seem to handle the case of link.leader == null && !showWhenUnlinked
. I assume in that case we should just return null?
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.
Fixed
/// a [Size] is provided to this layer, then find will check if the provided | ||
/// offset is within the bounds of the layer. | ||
class AnnotatedRegionLayer<T> extends ContainerLayer { | ||
/// Creates a new annotated layer. |
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.
These docs don't match our style guide.
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.
(Because they don't tell you anything you can't tell from the identifiers. Maybe mention the contract on size, e.g. that if null it won't clip, or something.)
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.
maybe say value can't be null? and assert it
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.
Fixed
/// The [size] is optionally used to clip the hit-testing of [find]. | ||
/// | ||
/// If not provided, all offsets are considered to be contained within this | ||
/// layer, unless a parent layer applies a clip. |
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.
a parent -> an ancestor
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.
Fixed
super.debugFillProperties(properties); | ||
properties.add(new DiagnosticsProperty<T>('value', value)); | ||
if (size != null) | ||
properties.add(new DiagnosticsProperty<Size>('size', size)); |
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.
you can always add this property, even if it's null. Just set defaultValue
to null.
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.
Fixed
/// * [Layer.find], for an example of how this value is retrieved. | ||
/// * [AnnotatedRegionLayer], the layer this render object creates. | ||
class AnnotatedRegionRenderObject<T> extends RenderProxyBox { | ||
/// A value which can be retrieved using [Layer.find]. |
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 lack of a constructor is very atypical for RenderObject subclasses.
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.
Fixed
/// * [AnnotatedRegionLayer], the layer this render object creates. | ||
class AnnotatedRegionRenderObject<T> extends RenderProxyBox { | ||
/// A value which can be retrieved using [Layer.find]. | ||
T value; |
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.
shouldn't changing value
cause markNeedsPaint
?
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.
Fixed
T value; | ||
|
||
/// Whether the render object will pass its [size] to the [AnnotatedRegionLayer]. | ||
bool sized; |
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.
similarly here, shouldn't mutating sized cause markNeedsPaint?
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.
Fixed
if (child != null) { | ||
final AnnotatedRegionLayer<T> layer = new AnnotatedRegionLayer<T>(value, size: sized ? size : null); | ||
context.pushLayer(layer, super.paint, offset); | ||
} |
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 do you only push the layer if there's a child?
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.
Fixed
@override | ||
void updateRenderObject(BuildContext context, AnnotatedRegionRenderObject<T> renderObject) { | ||
renderObject.value = value; | ||
renderObject.sized = sized; |
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.
prefer cascade operator; see other updateRenderObject implementations
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.
Fixed
Found issue with TestRecordingCanvas and with the location of the annotated region layer in app bar. Both fixes, should be all green |
/// object to clip the results of [Layer.findRegion]. | ||
/// | ||
/// Neither [value] nor [sized] can be null. | ||
AnnotatedRegionRenderObject(T value, bool sized) |
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.
btw the naming scheme is usually RenderFoo for the render object, and Foo for the widget.
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.
Fixed
: assert(value != null), | ||
assert(sized != null), | ||
_value = value, | ||
_sized = sized; |
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.
child?
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.
isn't that set by the element?
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 render object layer can be used directly, it doesn't have to be used via widgets. When used directly, the first child is usually set in the constructor. Look at the other classes in this file. :-)
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.
ahhh right, fixed
yaaay it passed |
Friendly ping. I've been informed this feature is a blocker for customer mulligan. |
Thanks for doing this, this is awesome! |
In order to fix the unpredictability of SystemChrome changes, I've added the AnnotatedRegion API as proposed by @Hixie on #4630.
Changes
AnnotatedRegion<T>
, a widget which places anAnnotatedRegionLayer<T>
in the layer tree.Layer.findRegion(Offset, Type)
which searches for the lastAnnotatedRegionLayer
that matchesType
and containsOffset
setSystemUiOverlayStyle
withAnnotatedRegion<SystemUiOverlayStyle>
setSystemUiOverlayStyle
after the layer tree is built usingfindRegion
.light
anddark
themes to always have dark app bars for Android - this is so enabling the default themes is non-breaking.Questions
Edit
Unfortunately I swapped the meaning of the brightness values for iOS in the engine, so I need to fix that separately