Skip to content

Commit

Permalink
[framework] ensure ink sparkle is disposed (#104569)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonahwilliams authored May 25, 2022
1 parent 09987dc commit 680a819
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 6 deletions.
11 changes: 10 additions & 1 deletion packages/flutter/lib/src/material/ink_sparkle.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ class InkSparkle extends InteractiveInkFeature {
_animationController = AnimationController(
duration: _animationDuration,
vsync: controller.vsync,
)..addListener(controller.markNeedsPaint)..forward();
)..addListener(controller.markNeedsPaint)
..addStatusListener(_handleStatusChanged)
..forward();

_radiusScale = TweenSequence<double>(
<TweenSequenceItem<double>>[
Expand Down Expand Up @@ -209,6 +211,11 @@ class InkSparkle extends InteractiveInkFeature {
_turbulenceSeed = turbulenceSeed ?? math.Random().nextDouble() * 1000.0;
}

void _handleStatusChanged(AnimationStatus status) {
if (status == AnimationStatus.completed)
dispose();
}

static const Duration _animationDuration = Duration(milliseconds: 617);
static const double _targetRadiusMultiplier = 2.3;
static const double _rotateRight = math.pi * 0.0078125;
Expand Down Expand Up @@ -259,6 +266,8 @@ class InkSparkle extends InteractiveInkFeature {

@override
void paintFeature(Canvas canvas, Matrix4 transform) {
assert(_animationController.isAnimating);

// InkSparkle can only paint if its shader has been compiled.
if (_InkSparkleFactory._shaderManager == null) {
// Skipping paintFeature because the shader it relies on is not ready to
Expand Down
6 changes: 6 additions & 0 deletions packages/flutter/lib/src/material/material.dart
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,12 @@ class _RenderInkFeatures extends RenderProxyBox implements MaterialInkController

bool absorbHitTest;

@visibleForTesting
List<InkFeature>? get debugInkFeatures {
if (kDebugMode)
return _inkFeatures;
return null;
}
List<InkFeature>? _inkFeatures;

@override
Expand Down
16 changes: 11 additions & 5 deletions packages/flutter/test/material/ink_sparkle_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,23 @@ void main() {
final Finder buttonFinder = find.text('Sparkle!');
await tester.tap(buttonFinder);
await tester.pump();
await tester.pumpAndSettle();
await tester.pump(const Duration(milliseconds: 200));

final MaterialInkController material = Material.of(tester.element(buttonFinder))!;
await tester.pump(const Duration(milliseconds: 200));
expect(material, paintsExactlyCountTimes(#drawRect, 1));

// ignore: avoid_dynamic_calls
expect((material as dynamic).debugInkFeatures, hasLength(1));

await tester.pumpAndSettle();
// ink feature is disposed.
// ignore: avoid_dynamic_calls
expect((material as dynamic).debugInkFeatures, isEmpty);
},
skip: kIsWeb, // [intended] SPIR-V shaders are not yet supported for web.
);

testWidgets('InkSparkle default splashFactory paints with drawPaint when unbounded', (WidgetTester tester) async {
testWidgets('InkSparkle default splashFactory paints with drawPaint when unbounded', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Center(
Expand All @@ -72,10 +79,9 @@ void main() {
final Finder buttonFinder = find.text('Sparkle!');
await tester.tap(buttonFinder);
await tester.pump();
await tester.pumpAndSettle();
await tester.pump(const Duration(milliseconds: 200));

final MaterialInkController material = Material.of(tester.element(buttonFinder))!;
await tester.pump(const Duration(milliseconds: 200));
expect(material, paintsExactlyCountTimes(#drawPaint, 1));
},
skip: kIsWeb, // [intended] SPIR-V shaders are not yet supported for web.
Expand Down

0 comments on commit 680a819

Please sign in to comment.