Unverified Commit e8d9d9bf authored by Kostia Sokolovskyi's avatar Kostia Sokolovskyi Committed by GitHub

HeroController should dispatch creation and disposal events. (#137835)

parent 0e7ed929
......@@ -156,6 +156,12 @@ class _CupertinoTabViewState extends State<CupertinoTabView> {
}
}
@override
void dispose() {
_heroController.dispose();
super.dispose();
}
void _updateObservers() {
_navigatorObservers =
List<NavigatorObserver>.of(widget.navigatorObservers)
......
......@@ -784,7 +784,17 @@ class HeroController extends NavigatorObserver {
///
/// The [createRectTween] argument is optional. If null, the controller uses a
/// linear [Tween<Rect>].
HeroController({ this.createRectTween });
HeroController({ this.createRectTween }) {
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectCreated(
library: 'package:flutter/widgets.dart',
className: '$HeroController',
object: this,
);
}
}
/// Used to create [RectTween]s that interpolate the position of heroes in flight.
///
......@@ -1043,6 +1053,12 @@ class HeroController extends NavigatorObserver {
/// Releases resources.
@mustCallSuper
void dispose() {
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
}
for (final _HeroFlight flight in _flights.values) {
flight.dispose();
}
......
......@@ -1060,6 +1060,7 @@ void main() {
testWidgetsWithLeakTracking('MaterialApp does create HeroController with the MaterialRectArcTween', (WidgetTester tester) async {
final HeroController controller = MaterialApp.createMaterialHeroController();
addTearDown(controller.dispose);
final Tween<Rect?> tween = controller.createRectTween!(
const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0),
const Rect.fromLTRB(0.0, 0.0, 20.0, 20.0),
......
......@@ -304,9 +304,12 @@ Future<void> main() async {
testWidgetsWithLeakTracking('Heroes still animate after hero controller is swapped.', (WidgetTester tester) async {
final GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>();
final UniqueKey heroKey = UniqueKey();
final HeroController controller1 = HeroController();
addTearDown(controller1.dispose);
await tester.pumpWidget(
HeroControllerScope(
controller: HeroController(),
controller: controller1,
child: TestDependencies(
child: Navigator(
key: key,
......@@ -352,15 +355,19 @@ Future<void> main() async {
);
},
));
expect(find.byKey(heroKey), findsNothing);
// Begins the navigation
await tester.pump();
await tester.pump(const Duration(milliseconds: 30));
expect(find.byKey(heroKey), isOnstage);
final HeroController controller2 = HeroController();
addTearDown(controller2.dispose);
// Pumps a new hero controller.
await tester.pumpWidget(
HeroControllerScope(
controller: HeroController(),
controller: controller2,
child: TestDependencies(
child: Navigator(
key: key,
......@@ -389,6 +396,7 @@ Future<void> main() async {
),
),
);
// The original animation still flies.
expect(find.byKey(heroKey), isOnstage);
// Waits for the animation finishes.
......@@ -3135,6 +3143,13 @@ Future<void> main() async {
await tester.pumpAndSettle();
expect(tester.getTopLeft(find.byType(Image)).dy, moreOrLessEquals(forwardRest, epsilon: 0.1));
});
test('HeroController dispatches memory events', () async {
await expectLater(
await memoryEvents(() => HeroController().dispose(), HeroController),
areCreateAndDispose,
);
});
}
class TestDependencies extends StatelessWidget {
......
......@@ -2367,6 +2367,8 @@ void main() {
),
);
};
addTearDown(spy.dispose);
await tester.pumpWidget(
HeroControllerScope(
controller: spy,
......@@ -2437,6 +2439,8 @@ void main() {
),
);
};
addTearDown(spy.dispose);
await tester.pumpWidget(
HeroControllerScope(
controller: spy,
......@@ -2506,6 +2510,7 @@ void main() {
),
);
};
addTearDown(spy1.dispose);
final List<NavigatorObservation> observations2 = <NavigatorObservation>[];
final HeroControllerSpy spy2 = HeroControllerSpy()
..onPushed = (Route<dynamic>? route, Route<dynamic>? previousRoute) {
......@@ -2517,6 +2522,8 @@ void main() {
),
);
};
addTearDown(spy2.dispose);
await tester.pumpWidget(
TestDependencies(
child: Stack(
......@@ -2633,6 +2640,8 @@ void main() {
testWidgetsWithLeakTracking('hero controller subscribes to multiple navigators does throw', (WidgetTester tester) async {
final HeroControllerSpy spy = HeroControllerSpy();
addTearDown(spy.dispose);
await tester.pumpWidget(
HeroControllerScope(
controller: spy,
......@@ -2671,6 +2680,8 @@ void main() {
testWidgetsWithLeakTracking('hero controller throws has correct error message', (WidgetTester tester) async {
final HeroControllerSpy spy = HeroControllerSpy();
addTearDown(spy.dispose);
await tester.pumpWidget(
HeroControllerScope(
controller: spy,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment