twonly-app-dependencies/lottie/test/dynamic_properties_test.dart
2025-12-07 16:10:41 +01:00

478 lines
10 KiB
Dart

import 'dart:io';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lottie/lottie.dart';
import 'utils.dart';
void main() {
void testGolden(
String description,
ValueDelegate delegate, {
double? progress,
String? filePath,
}) {
filePath ??= 'Tests/Shapes.json';
var screenshotName = description
.toLowerCase()
.replaceAll(RegExp('[^a-z0-9 ]'), '')
.replaceAll(' ', '_');
testWidgets(description, (tester) async {
var composition = await LottieComposition.fromBytes(
File('example/assets/$filePath').readAsBytesSync(),
);
var animation = AnimationController(
vsync: tester,
duration: composition.duration,
);
if (progress != null) {
animation.value = progress;
}
await tester.pumpWidget(
Lottie(
composition: composition,
controller: animation,
delegates: LottieDelegates(values: [delegate]),
addRepaintBoundary: false,
),
);
await tester.pump();
await expectLater(
find.byType(Lottie),
matchesGoldenFile('goldens/dynamic/$screenshotName.png'),
);
if (progress == null || progress == 0) {
await tester.pumpWidget(
Lottie(
composition: composition,
controller: animation,
delegates: const LottieDelegates(values: []),
addRepaintBoundary: false,
),
);
await tester.pump();
}
});
}
testGolden(
'Fill color (Green)',
ValueDelegate.color([
'Shape Layer 1',
'Rectangle',
'Fill 1',
], value: Colors.green),
);
testGolden(
'Fill color (Yellow)',
ValueDelegate.color([
'Shape Layer 1',
'Rectangle',
'Fill 1',
], value: Colors.yellow),
);
testGolden(
'Fill opacity',
ValueDelegate.opacity(['Shape Layer 1', 'Rectangle', 'Fill 1'], value: 50),
);
testGolden(
'Stroke color',
ValueDelegate.strokeColor([
'Shape Layer 1',
'Rectangle',
'Stroke 1',
], value: Colors.green),
);
testGolden(
'Stroke width',
ValueDelegate.strokeWidth([
'Shape Layer 1',
'Rectangle',
'Stroke 1',
], value: 50),
);
testGolden(
'Stroke opacity',
ValueDelegate.opacity([
'Shape Layer 1',
'Rectangle',
'Stroke 1',
], value: 50),
);
testGolden(
'Transform anchor point',
ValueDelegate.transformAnchorPoint([
'Shape Layer 1',
'Rectangle',
], value: const Offset(20, 20)),
);
testGolden(
'Transform position',
ValueDelegate.transformPosition([
'Shape Layer 1',
'Rectangle',
], value: const Offset(20, 20)),
);
testGolden(
'Transform position (relative)',
ValueDelegate.transformPosition([
'Shape Layer 1',
'Rectangle',
], relative: const Offset(20, 20)),
);
testGolden(
'Transform opacity',
ValueDelegate.transformOpacity(['Shape Layer 1', 'Rectangle'], value: 50),
);
testGolden(
'Transform rotation',
ValueDelegate.transformRotation(['Shape Layer 1', 'Rectangle'], value: 45),
);
testGolden(
'Transform scale',
ValueDelegate.transformScale([
'Shape Layer 1',
'Rectangle',
], value: const Offset(0.5, 0.5)),
);
testGolden(
'Rectangle corner roundedness',
ValueDelegate.cornerRadius([
'Shape Layer 1',
'Rectangle',
'Rectangle Path 1',
], value: 7),
);
testGolden(
'Rectangle position',
ValueDelegate.position([
'Shape Layer 1',
'Rectangle',
'Rectangle Path 1',
], relative: const Offset(20, 20)),
);
testGolden(
'Rectangle size',
ValueDelegate.rectangleSize([
'Shape Layer 1',
'Rectangle',
'Rectangle Path 1',
], relative: const Offset(30, 40)),
);
testGolden(
'Ellipse position',
ValueDelegate.position([
'Shape Layer 1',
'Ellipse',
'Ellipse Path 1',
], relative: const Offset(20, 20)),
);
testGolden(
'Ellipse size',
ValueDelegate.ellipseSize([
'Shape Layer 1',
'Ellipse',
'Ellipse Path 1',
], relative: const Offset(40, 60)),
);
testGolden(
'Star points',
ValueDelegate.polystarPoints([
'Shape Layer 1',
'Star',
'Polystar Path 1',
], value: 8),
);
testGolden(
'Star rotation',
ValueDelegate.polystarRotation([
'Shape Layer 1',
'Star',
'Polystar Path 1',
], value: 10),
);
testGolden(
'Star position',
ValueDelegate.position([
'Shape Layer 1',
'Star',
'Polystar Path 1',
], relative: const Offset(20, 20)),
);
testGolden(
'Star inner radius',
ValueDelegate.polystarInnerRadius([
'Shape Layer 1',
'Star',
'Polystar Path 1',
], value: 10),
);
testGolden(
'Star inner roundedness',
ValueDelegate.polystarInnerRoundedness([
'Shape Layer 1',
'Star',
'Polystar Path 1',
], value: 100),
);
testGolden(
'Star outer radius',
ValueDelegate.polystarOuterRadius([
'Shape Layer 1',
'Star',
'Polystar Path 1',
], value: 60),
);
testGolden(
'Star outer roundedness',
ValueDelegate.polystarOuterRoundedness([
'Shape Layer 1',
'Star',
'Polystar Path 1',
], value: 100),
);
testGolden(
'Polygon points',
ValueDelegate.polystarPoints([
'Shape Layer 1',
'Star',
'Polystar Path 1',
], value: 8),
);
testGolden(
'Polygon rotation',
ValueDelegate.polystarRotation([
'Shape Layer 1',
'Star',
'Polystar Path 1',
], value: 10),
);
testGolden(
'Polygon position',
ValueDelegate.position([
'Shape Layer 1',
'Star',
'Polystar Path 1',
], relative: const Offset(20, 20)),
);
testGolden(
'Polygon radius',
ValueDelegate.polystarOuterRadius([
'Shape Layer 1',
'Star',
'Polystar Path 1',
], relative: 60),
);
testGolden(
'Polygon roundedness',
ValueDelegate.polystarOuterRoundedness([
'Shape Layer 1',
'Star',
'Polystar Path 1',
], value: 100),
);
testGolden(
'Repeater transform position',
ValueDelegate.transformPosition([
'Shape Layer 1',
'Repeater Shape',
'Repeater 1',
], relative: const Offset(100, 100)),
);
testGolden(
'Repeater transform start opacity',
ValueDelegate.transformStartOpacity([
'Shape Layer 1',
'Repeater Shape',
'Repeater 1',
], value: 25),
);
testGolden(
'Repeater transform end opacity',
ValueDelegate.transformEndOpacity([
'Shape Layer 1',
'Repeater Shape',
'Repeater 1',
], value: 25),
);
testGolden(
'Repeater transform rotation',
ValueDelegate.transformRotation([
'Shape Layer 1',
'Repeater Shape',
'Repeater 1',
], value: 45),
);
testGolden(
'Repeater transform scale',
ValueDelegate.transformScale([
'Shape Layer 1',
'Repeater Shape',
'Repeater 1',
], value: const Offset(2, 2)),
);
testGolden(
'Time remapping',
ValueDelegate.timeRemap(['Circle 1'], value: 1),
progress: 0.1,
);
testGolden(
'Color Filter',
ValueDelegate.colorFilter([
'**',
], value: const ColorFilter.mode(Colors.green, BlendMode.srcATop)),
);
testGolden('Null Color Filter', ValueDelegate.colorFilter(['**']));
testGolden(
'Matte property',
ValueDelegate.rectangleSize([
'Shape Layer 1',
'Rectangle 1',
'Rectangle Path 1',
], value: const Offset(50, 50)),
filePath: 'Tests/TrackMattes.json',
);
testGolden('Blur', ValueDelegate.blurRadius(['**'], value: 10));
testGolden(
'Drop shadow',
ValueDelegate.dropShadow(
['Shape Layer 1', '**'],
value: const DropShadow(
color: Colors.green,
direction: 150,
distance: 20,
radius: 10,
),
),
);
testGolden(
'Solid Color',
ValueDelegate.color(['Cyan Solid 1', '**'], value: Colors.yellow),
filePath: 'Tests/SolidLayerTransform.json',
);
for (var progress in [0.0, 0.5, 1.0]) {
testGolden(
'Opacity interpolation ($progress)',
ValueDelegate.transformOpacity(
['Shape Layer 1', 'Rectangle'],
callback: (frameInfo) => lerpDouble(
10,
100,
Curves.linear.transform(frameInfo.overallProgress),
)!.round(),
),
progress: progress,
);
}
testWidgets('warningShimmer', (tester) async {
var size = const Size(500, 400);
tester.view.physicalSize = size;
tester.view.devicePixelRatio = 1.0;
var composition = await LottieComposition.fromBytes(
File('test/data/warningShimmer.json').readAsBytesSync(),
);
var delegates = <String, List<ValueDelegate>>{
'1': [
for (var i in ['1', '2', '5'])
ValueDelegate.color(['Layer $i Outlines', '**'], value: Colors.red),
for (var i in ['3', '4'])
ValueDelegate.color([
'Layer $i Outlines',
'**',
], value: Colors.greenAccent),
],
'2': [
for (var i in ['1', '2', '5'])
ValueDelegate.color([
'Layer $i Outlines',
'Group 1',
'*',
], value: Colors.red),
for (var i in ['3', '4'])
ValueDelegate.color([
'Layer $i Outlines',
'Group 1',
'*',
], value: Colors.greenAccent),
],
'3': [
for (var i in ['1', '2', '5'])
ValueDelegate.color([
'Layer $i Outlines',
'Group 1',
'Fill 1',
], value: Colors.red),
for (var i in ['3', '4'])
ValueDelegate.color([
'Layer $i Outlines',
'Group 1',
'Fill 1',
], value: Colors.greenAccent),
],
};
for (var variant in delegates.entries) {
await tester.pumpWidget(
FilmStrip(
composition,
size: size,
delegates: LottieDelegates(values: variant.value),
),
);
await expectLater(
find.byType(FilmStrip),
matchesGoldenFile('goldens/warningShimmer_${variant.key}.png'),
);
}
});
}