Compare commits

..

11 Commits

144 changed files with 2492 additions and 797 deletions

View File

@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
flutter: ['stable', 'dev']
runs-on: ubuntu-latest
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v1
@ -19,12 +19,16 @@ jobs:
channel: ${{ matrix.flutter }}
- run: flutter doctor
- run: flutter --version
- run: flutter pub get
working-directory: example
- run: flutter analyze
- run: flutter test test # https://github.com/flutter/flutter/issues/20907
- run: flutter test test
working-directory: example
- run: flutter pub run tool/prepare_submit.dart
- name: "check for uncommitted changes"
run: |
git diff --exit-code --stat -- . \
git diff --exit-code --stat -- . ':(exclude)*pubspec.lock' \
|| (echo "##[error] found changed files after build. please run 'dart tool/prepare_submit.dart'" \
"and check in all changes" \
&& exit 1)

2
.gitignore vendored
View File

@ -4,6 +4,8 @@ _*
!.gitignore
!.github
**/failures/*.png
*.iml
**/doc/api/
build/

View File

@ -1,3 +1,15 @@
## [0.3.1] - 2020-03-05
- Support dashed path
## [0.3.0+1] - 2020-03-05
- Specify a version range for the dependency on `characters`.
## [0.3.0] - 2020-03-05
- Add `LottieDelegates` a group of options to customize the lottie animation at runtime.
ie: Dynamically modify color, position, size, text... of every elements of the animation.
- Correctly display Linear and Radial Gradients
- Integrate latest changes from Lottie-android
## [0.2.2] - 2020-02-21
- Add a [repeat] parameter to specify if the automatic animation should loop.
- Add the [animate], [reverse], [repeat] properties on `LottieBuilder`

22
LICENSE
View File

@ -1 +1,21 @@
TODO: Add your license here.
MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -4,7 +4,7 @@
[![pub package](https://img.shields.io/pub/v/lottie.svg)](https://pub.dev/packages/lottie)
Lottie is a mobile library for Android and iOS that parses [Adobe After Effects](http://www.adobe.com/products/aftereffects.html)
animations exported as json with [Bodymovin](https://github.com/bodymovin/bodymovin) and renders them natively on mobile!
animations exported as json with [Bodymovin](https://github.com/airbnb/lottie-web) and renders them natively on mobile!
This repository is a unofficial conversion of the [Lottie-android](https://github.com/airbnb/lottie-android) library in pure Dart.
@ -37,7 +37,7 @@ class MyApp extends StatelessWidget {
'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/A.json'),
// Load an animation and its images from a zip file
Lottie.asset('assets/lottiesfiles/angel.zip'),
Lottie.asset('assets/lottiefiles/angel.zip'),
],
),
),
@ -46,15 +46,8 @@ class MyApp extends StatelessWidget {
}
```
To load an animation from the assets folder, we need to add an `assets` section in the `pubspec.yaml`:
```yaml
flutter:
assets:
- assets/
```
### Specify a custom `AnimationController`
This example shows how to have full control over the animation by providing your own `AnimationController`.
This example shows how to take full control over the animation by providing your own `AnimationController`.
```dart
import 'package:flutter/material.dart';
@ -90,7 +83,7 @@ class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
body: ListView(
children: [
Lottie.network(
'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/sample_app/assets/Mobilo/C.json',
'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/C.json',
controller: _controller,
onLoaded: (composition) {
// Configure the AnimationController with the duration of the
@ -201,7 +194,9 @@ class _Painter extends CustomPainter {
var columns = 10;
for (var i = 0; i < frameCount; i++) {
var destRect = Offset(i % columns * 50.0, i ~/ 10 * 80.0) & (size / 5);
drawable.draw(canvas, destRect, progress: i / frameCount);
drawable
..setProgress(i / frameCount)
..draw(canvas, destRect);
}
}
@ -212,14 +207,44 @@ class _Painter extends CustomPainter {
}
````
### Modify properties at runtime
This example shows how to modify some properties of the animation at runtime. Here we change the text,
the color, the opacity and the position of some layers.
For each `ValueDelegate` we can either provide a static `value` or a `callback` to compute a value for a each frame.
````dart
class _Animation extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Lottie.asset(
'assets/Tests/Shapes.json',
delegates: LottieDelegates(
text: (initialText) => translate(initialText),
values: [
ValueDelegate.color(
const ['Shape Layer 1', 'Rectangle', 'Fill 1'],
value: Colors.red,
),
ValueDelegate.opacity(
const ['Shape Layer 1', 'Rectangle'],
callback: (frameInfo) =>
(frameInfo.overallProgress * 100).round(),
),
ValueDelegate.position(
const ['Shape Layer 1', 'Rectangle'],
relative: Offset(100, 200),
),
]),
);
}
}
````
## Limitations
This is a new library so usability, documentation and performance are still work in progress.
The following features are not yet implemented:
- Dash path effects
- Transforms on gradients (stroke and fills)
- Expose `Value callback` to modify dynamically some properties of the animation
- Text in animations has very basic support (unoptimized and buggy)
Only the [supported features of Lottie Android](https://airbnb.io/lottie/#/supported-features)
are supported in this port.
## Flutter Web
Run the app with `flutter run -d Chrome --dart-define=FLUTTER_WEB_USE_SKIA=true --release`

View File

@ -4,7 +4,7 @@
[![pub package](https://img.shields.io/pub/v/lottie.svg)](https://pub.dev/packages/lottie)
Lottie is a mobile library for Android and iOS that parses [Adobe After Effects](http://www.adobe.com/products/aftereffects.html)
animations exported as json with [Bodymovin](https://github.com/bodymovin/bodymovin) and renders them natively on mobile!
animations exported as json with [Bodymovin](https://github.com/airbnb/lottie-web) and renders them natively on mobile!
This repository is a unofficial conversion of the [Lottie-android](https://github.com/airbnb/lottie-android) library in pure Dart.
@ -20,15 +20,8 @@ The `Lottie` widget will load the json file and run the animation indefinitely.
import 'example/lib/examples/main.dart';
```
To load an animation from the assets folder, we need to add an `assets` section in the `pubspec.yaml`:
```yaml
flutter:
assets:
- assets/
```
### Specify a custom `AnimationController`
This example shows how to have full control over the animation by providing your own `AnimationController`.
This example shows how to take full control over the animation by providing your own `AnimationController`.
```dart
import 'example/lib/examples/animation_controller.dart';
@ -69,14 +62,20 @@ a specific position and size.
import 'example/lib/examples/custom_draw.dart#example';
````
### Modify properties at runtime
This example shows how to modify some properties of the animation at runtime. Here we change the text,
the color, the opacity and the position of some layers.
For each `ValueDelegate` we can either provide a static `value` or a `callback` to compute a value for a each frame.
````dart
import 'example/lib/examples/simple_dynamic_properties.dart#example';
````
## Limitations
This is a new library so usability, documentation and performance are still work in progress.
The following features are not yet implemented:
- Dash path effects
- Transforms on gradients (stroke and fills)
- Expose `Value callback` to modify dynamically some properties of the animation
- Text in animations has very basic support (unoptimized and buggy)
Only the [supported features of Lottie Android](https://airbnb.io/lottie/#/supported-features)
are supported in this port.
## Flutter Web
Run the app with `flutter run -d Chrome --dart-define=FLUTTER_WEB_USE_SKIA=true --release`

View File

@ -3,6 +3,7 @@ analyzer:
errors:
strong-mode:
implicit-casts: false
implicit-dynamic: false
linter:
rules:
avoid_renaming_method_parameters: true

View File

@ -0,0 +1,185 @@
{
"v": "5.5.7",
"meta": {
"g": "LottieFiles AE 0.1.14",
"a": "",
"k": "",
"d": "",
"tc": ""
},
"fr": 60,
"ip": 0,
"op": 180,
"w": 300,
"h": 300,
"nm": " Square",
"ddd": 0,
"assets": [],
"layers": [
{
"ddd": 0,
"ind": 1,
"ty": 4,
"nm": "Shape Layer 1",
"sr": 1,
"ks": {
"o": {
"a": 0,
"k": 100,
"ix": 11
},
"r": {
"a": 0,
"k": 0,
"ix": 10
},
"p": {
"a": 0,
"k": [
150,
150,
0
],
"ix": 2
},
"a": {
"a": 0,
"k": [
0,
0,
0
],
"ix": 1
},
"s": {
"a": 0,
"k": [
100,
100,
100
],
"ix": 6
}
},
"ao": 0,
"shapes": [
{
"ty": "gr",
"it": [
{
"ty": "rc",
"d": 1,
"s": {
"a": 0,
"k": [
182.992,
182.992
],
"ix": 2
},
"p": {
"a": 0,
"k": [
0,
0
],
"ix": 3
},
"r": {
"a": 0,
"k": 0,
"ix": 4
},
"nm": "Rectangle Path 1",
"mn": "ADBE Vector Shape - Rect",
"hd": false
},
{
"ty": "fl",
"c": {
"a": 0,
"k": [
1,
0,
0,
255
],
"ix": 4
},
"o": {
"a": 0,
"k": 100,
"ix": 5
},
"r": 1,
"bm": 0,
"nm": "Fill 1",
"mn": "ADBE Vector Graphic - Fill",
"hd": false
},
{
"ty": "tr",
"p": {
"a": 0,
"k": [
-8.504,
1.496
],
"ix": 2
},
"a": {
"a": 0,
"k": [
0,
0
],
"ix": 1
},
"s": {
"a": 0,
"k": [
100,
100
],
"ix": 3
},
"r": {
"a": 0,
"k": 0,
"ix": 6
},
"o": {
"a": 0,
"k": 100,
"ix": 7
},
"sk": {
"a": 0,
"k": 0,
"ix": 4
},
"sa": {
"a": 0,
"k": 0,
"ix": 5
},
"nm": "Transform"
}
],
"nm": "Rectangle 1",
"np": 2,
"cix": 2,
"bm": 0,
"ix": 1,
"mn": "ADBE Vector Group",
"hd": false
}
],
"ip": 0,
"op": 180,
"st": 0,
"bm": 0
}
],
"markers": []
}

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
void main() async {
runApp(App());
}
class App extends StatefulWidget {
const App({Key key}) : super(key: key);
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return MaterialApp(
color: Colors.lightBlue,
home: Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
title: Text(''),
),
body: Center(
child: SizedBox(
width: 300,
height: 300,
child: Lottie.asset(
'assets/LottieLogo1.json',
animate: true,
repeat: false,
),
),
),
),
);
}
}

View File

@ -31,7 +31,7 @@ class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
body: ListView(
children: [
Lottie.network(
'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/sample_app/assets/Mobilo/C.json',
'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/C.json',
controller: _controller,
onLoaded: (composition) {
// Configure the AnimationController with the duration of the

View File

@ -81,7 +81,9 @@ class _Painter extends CustomPainter {
var columns = 10;
for (var i = 0; i < frameCount; i++) {
var destRect = Offset(i % columns * 50.0, i ~/ 10 * 80.0) & (size / 5);
drawable.draw(canvas, destRect, progress: i / frameCount);
drawable
..setProgress(i / frameCount)
..draw(canvas, destRect);
}
}

View File

@ -0,0 +1,86 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:lottie/lottie.dart';
void main() async {
runApp(App());
}
class App extends StatefulWidget {
const App({Key key}) : super(key: key);
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> with TickerProviderStateMixin {
Color _color = Colors.green;
double _opacity = 0.5;
bool _useDelegates = true;
@override
Widget build(BuildContext context) {
var valueDelegates = [
ValueDelegate.color(['Shape Layer 1', 'Rectangle', 'Fill 1'],
value: _color),
ValueDelegate.opacity(['Shape Layer 1', 'Rectangle', 'Fill 1'],
callback: (_) => (_opacity * 100).round()),
];
return MaterialApp(
color: Colors.blue,
home: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('Dynamic properties'),
),
body: ListView(
children: <Widget>[
SizedBox(
width: 300,
height: 300,
child: Lottie.asset(
'assets/Tests/Shapes.json',
delegates: LottieDelegates(
values: _useDelegates ? valueDelegates : null),
),
),
Checkbox(
value: _useDelegates,
onChanged: (newValue) {
setState(() {
_useDelegates = newValue;
});
},
),
Slider(
value: _opacity,
onChanged: (newOpacity) {
setState(() {
_opacity = newOpacity;
});
},
),
Center(
child: Container(
width: 500,
child: ColorPicker(
pickerColor: _color,
onColorChanged: (newColor) {
setState(() {
_color = newColor;
});
},
showLabel: false,
enableAlpha: false,
pickerAreaHeightPercent: 0.8,
),
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,72 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
void main() async {
runApp(App());
}
class App extends StatefulWidget {
const App({Key key}) : super(key: key);
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> with TickerProviderStateMixin {
TextEditingController _textController;
@override
void initState() {
super.initState();
_textController = TextEditingController(text: /*'🔥Fire🔥'*/ 'Fire');
}
@override
void dispose() {
_textController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
color: Colors.blue,
home: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('Dynamic text'),
),
body: Center(
child: Column(
children: <Widget>[
SizedBox(
width: 300,
height: 300,
child: Lottie.asset(
'assets/Tests/DynamicText.json',
delegates: LottieDelegates(
text: (animationText) => _textController.text,
textStyle: (font) => TextStyle(
fontFamily: font.fontFamily,
fontStyle: FontStyle.italic),
),
),
),
Container(
width: 300,
child: CupertinoTextField(
controller: _textController,
onChanged: (newText) {
setState(() {});
},
),
)
],
),
),
),
);
}
}

View File

@ -0,0 +1,70 @@
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
void main() async {
runApp(App());
}
class App extends StatefulWidget {
const App({Key key}) : super(key: key);
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> with TickerProviderStateMixin {
AnimationController _animationController;
bool _showAnimation = true;
@override
void initState() {
super.initState();
_animationController = AnimationController(vsync: this)
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
setState(() {
_showAnimation = false;
});
}
});
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
color: Colors.lightBlue,
home: Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
title: Text('Show lottie animation: $_showAnimation'),
),
body: SingleChildScrollView(
child: Center(
child: Column(
children: [
if (_showAnimation)
Lottie.asset(
'assets/LottieLogo1.json',
controller: _animationController,
width: 200,
onLoaded: (composition) {
_animationController
..duration = composition.duration
..reset()
..forward();
},
),
],
),
),
),
),
);
}
}

View File

@ -18,7 +18,7 @@ class MyApp extends StatelessWidget {
'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/A.json'),
// Load an animation and its images from a zip file
Lottie.asset('assets/lottiesfiles/angel.zip'),
Lottie.asset('assets/lottiefiles/angel.zip'),
],
),
),

View File

@ -0,0 +1,71 @@
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:lottie/lottie.dart';
import '../src/all_files.g.dart';
void main() async {
Logger.root
..level = Level.ALL
..onRecord.listen(print);
runApp(App());
}
class App extends StatefulWidget {
const App({Key key}) : super(key: key);
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> with TickerProviderStateMixin {
int _index = 0;
AnimationController _animationController;
@override
void initState() {
super.initState();
_animationController = AnimationController(vsync: this)
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
setState(() {
++_index;
});
}
});
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
color: Colors.lightBlue,
home: Scaffold(
backgroundColor: Colors.lightBlue,
appBar: AppBar(
title: Text('$_index'),
),
body: SingleChildScrollView(
child: Center(
child: Column(
children: [
Lottie.asset(files[_index % files.length],
controller: _animationController, onLoaded: (composition) {
_animationController
..duration = composition.duration
..reset()
..forward();
}),
],
),
),
),
),
);
}
}

View File

@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListView(
children: [_Animation()],
),
),
);
}
}
String translate(String input) => '**$input**';
//--- example
class _Animation extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Lottie.asset(
'assets/Tests/Shapes.json',
delegates: LottieDelegates(
text: (initialText) => translate(initialText),
values: [
ValueDelegate.color(
const ['Shape Layer 1', 'Rectangle', 'Fill 1'],
value: Colors.red,
),
ValueDelegate.opacity(
const ['Shape Layer 1', 'Rectangle'],
callback: (frameInfo) =>
(frameInfo.overallProgress * 100).round(),
),
ValueDelegate.position(
const ['Shape Layer 1', 'Rectangle'],
relative: Offset(100, 200),
),
]),
);
}
}
//---

View File

@ -2,14 +2,13 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:lottie/lottie.dart';
import 'package:lottie/src/l.dart';
import 'src/all_files.g.dart';
void main() {
Logger.root
..level = Level.ALL
..onRecord.listen(print);
L.setTraceEnabled(true);
Lottie.traceEnabled = true;
runApp(App());
}
@ -43,8 +42,8 @@ class App extends StatelessWidget {
),
),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => Detail(assetName)));
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (context) => Detail(assetName)));
},
);
},
@ -66,7 +65,6 @@ class _Item extends StatelessWidget {
child: Container(
decoration: BoxDecoration(
color: Colors.white,
//border: Border.all(color: Colors.black12),
borderRadius: BorderRadius.all(Radius.circular(10)),
boxShadow: [
BoxShadow(

View File

@ -1,341 +1,343 @@
// Generated from tool/generate_file_list.dart
final files = [
'assets/14595-thumbs-up.json',
'assets/Mobilo/T.json',
'assets/AndroidWave.json',
'assets/DynamicGradient.json',
'assets/HamburgerArrow.json',
'assets/Logo/LogoSmall.json',
'assets/LottieLogo1.json',
'assets/LottieLogo2.json',
'assets/Mobilo/A.json',
'assets/Mobilo/X.json',
'assets/Mobilo/BlinkingCursor.json',
'assets/Mobilo/M.json',
'assets/Mobilo/L.json',
'assets/Mobilo/Y.json',
'assets/Mobilo/U.json',
'assets/Mobilo/K.json',
'assets/Mobilo/R.json',
'assets/Mobilo/G.json',
'assets/Mobilo/F.json',
'assets/Mobilo/S.json',
'assets/Mobilo/J.json',
'assets/Mobilo/I.json',
'assets/Mobilo/E.json',
'assets/Mobilo/Apostrophe.json',
'assets/Mobilo/B.json',
'assets/Mobilo/BlinkingCursor.json',
'assets/Mobilo/C.json',
'assets/Mobilo/Colon.json',
'assets/Mobilo/Comma.json',
'assets/Mobilo/D.json',
'assets/Mobilo/E.json',
'assets/Mobilo/F.json',
'assets/Mobilo/G.json',
'assets/Mobilo/H.json',
'assets/Mobilo/I.json',
'assets/Mobilo/J.json',
'assets/Mobilo/K.json',
'assets/Mobilo/L.json',
'assets/Mobilo/M.json',
'assets/Mobilo/N.json',
'assets/Mobilo/O.json',
'assets/Mobilo/P.json',
'assets/Mobilo/Q.json',
'assets/Mobilo/D.json',
'assets/Mobilo/Colon.json',
'assets/Mobilo/H.json',
'assets/Mobilo/C.json',
'assets/Mobilo/R.json',
'assets/Mobilo/S.json',
'assets/Mobilo/T.json',
'assets/Mobilo/U.json',
'assets/Mobilo/V.json',
'assets/Mobilo/Comma.json',
'assets/Mobilo/O.json',
'assets/Mobilo/Z.json',
'assets/Mobilo/N.json',
'assets/Mobilo/W.json',
'assets/Mobilo/B.json',
'assets/HamburgerArrow.json',
'assets/Tests/Remap.json',
'assets/Tests/Airbnb400.zip',
'assets/Tests/catrim_converted.json',
'assets/Tests/StartEndFrame.json',
'assets/Tests/TrackMattes.json',
'assets/Tests/DynamicText.json',
'assets/Tests/Precomps.json',
'assets/Tests/2ParentsMatte.json',
'assets/Mobilo/X.json',
'assets/Mobilo/Y.json',
'assets/Mobilo/Z.json',
'assets/Tests/2FrameAnimation.json',
'assets/Tests/LoopPlayOnce.json',
'assets/Tests/bm_converted.json',
'assets/Tests/RGBMarker.json',
'assets/Tests/WeAccept.json',
'assets/Tests/MiterLimit.json',
'assets/Tests/dalek.json',
'assets/Tests/MaskInv.json',
'assets/Tests/MatteTimeStretchScan.json',
'assets/Tests/Marker.json',
'assets/Tests/TrimPathsInsideAndOutsideGroup.json',
'assets/Tests/MaskNone.json',
'assets/Tests/Text_Justification_Translate_Scale_Rotation_Text.json',
'assets/Tests/InterpolatorLoopBack.json',
'assets/Tests/SplitDimensions.json',
'assets/Tests/EndFrame.json',
'assets/Tests/RGB.json',
'assets/Tests/DynamicGradient.json',
'assets/Tests/Font_Text_Justification_Translate_Scale_Rotation_Test.json',
'assets/Tests/adrock_converted.json',
'assets/Tests/ShapeTypes.json',
'assets/Tests/Squares.json',
'assets/Tests/Parenting.json',
'assets/Tests/catrim.json',
'assets/Tests/Stroke.json',
'assets/Tests/TimeStretch.json',
'assets/Tests/CheckSwitch.json',
'assets/Tests/hd.json',
'assets/Tests/OverlapShapeWithOpacity.json',
'assets/Tests/Shapes.json',
'assets/Tests/Masks.json',
'assets/Tests/SolidLayerTransform.json',
'assets/Tests/WeAcceptInlineImage.json',
'assets/Tests/TrimPaths.json',
'assets/Tests/2ParentsMatte.json',
'assets/Tests/Airbnb.zip',
'assets/Tests/DifferentPointsCount.json',
'assets/Tests/Skew.json',
'assets/Tests/GradientFill.json',
'assets/Tests/TransformWithoutEndValues.json',
'assets/Tests/EllipseDirection.json',
'assets/Tests/TimeStretchMask.json',
'assets/Tests/Frame.json',
'assets/Tests/map.zip',
'assets/Tests/august_view_pulse.zip',
'assets/Tests/KeyframeTypes.json',
'assets/Tests/dalek_converted.json',
'assets/Tests/Laugh4.json',
'assets/Tests/Scale0.json',
'assets/Tests/StarSkew.json',
'assets/Tests/TextBaseline.json',
'assets/Tests/Text.json',
'assets/Tests/bm.json',
'assets/Tests/Fill.json',
'assets/Tests/MaskA.json',
'assets/Tests/Repeater.json',
'assets/Tests/TimeStretchPrecomp.json',
'assets/Tests/adrock.json',
'assets/Tests/MatteTimeStretchLine.json',
'assets/Tests/Airbnb400.zip',
'assets/Tests/Airbnb800.zip',
'assets/DynamicGradient.json',
'assets/LottieLogo2.json',
'assets/AndroidWave.json',
'assets/LottieLogo1.json',
'assets/Logo/LogoSmall.json',
'assets/lottiefiles/the_final_frontier.json',
'assets/Tests/CheckSwitch.json',
'assets/Tests/DifferentPointsCount.json',
'assets/Tests/DynamicGradient.json',
'assets/Tests/DynamicText.json',
'assets/Tests/EllipseDirection.json',
'assets/Tests/EndFrame.json',
'assets/Tests/Fill.json',
'assets/Tests/Font_Text_Justification_Translate_Scale_Rotation_Test.json',
'assets/Tests/Frame.json',
'assets/Tests/GradientFill.json',
'assets/Tests/InterpolatorLoopBack.json',
'assets/Tests/KeyframeTypes.json',
'assets/Tests/Laugh4.json',
'assets/Tests/LoopPlayOnce.json',
'assets/Tests/Marker.json',
'assets/Tests/MaskA.json',
'assets/Tests/MaskInv.json',
'assets/Tests/MaskNone.json',
'assets/Tests/Masks.json',
'assets/Tests/MatteTimeStretchLine.json',
'assets/Tests/MatteTimeStretchScan.json',
'assets/Tests/MiterLimit.json',
'assets/Tests/OverlapShapeWithOpacity.json',
'assets/Tests/Parenting.json',
'assets/Tests/Precomps.json',
'assets/Tests/RGB.json',
'assets/Tests/RGBMarker.json',
'assets/Tests/Remap.json',
'assets/Tests/Repeater.json',
'assets/Tests/Scale0.json',
'assets/Tests/ShapeTypes.json',
'assets/Tests/Shapes.json',
'assets/Tests/Skew.json',
'assets/Tests/SolidLayerTransform.json',
'assets/Tests/SplitDimensions.json',
'assets/Tests/Squares.json',
'assets/Tests/StarSkew.json',
'assets/Tests/StartEndFrame.json',
'assets/Tests/Stroke.json',
'assets/Tests/TelegramAlphaCompat.json',
'assets/Tests/Text.json',
'assets/Tests/TextBaseline.json',
'assets/Tests/Text_Justification_Translate_Scale_Rotation_Text.json',
'assets/Tests/TimeRemapAndStartOffset.json',
'assets/Tests/TimeStretch.json',
'assets/Tests/TimeStretchMask.json',
'assets/Tests/TimeStretchPrecomp.json',
'assets/Tests/TrackMattes.json',
'assets/Tests/TransformWithoutEndValues.json',
'assets/Tests/TrimPaths.json',
'assets/Tests/TrimPathsInsideAndOutsideGroup.json',
'assets/Tests/WeAccept.json',
'assets/Tests/WeAcceptInlineImage.json',
'assets/Tests/adrock.json',
'assets/Tests/adrock_converted.json',
'assets/Tests/august_view_pulse.zip',
'assets/Tests/bm.json',
'assets/Tests/bm_converted.json',
'assets/Tests/catrim.json',
'assets/Tests/catrim_converted.json',
'assets/Tests/dalek.json',
'assets/Tests/dalek_converted.json',
'assets/Tests/hd.json',
'assets/Tests/map.zip',
'assets/lf20_w2Afea.json',
'assets/lottiefiles/100_percent.json',
'assets/lottiefiles/Plane.json',
'assets/lottiefiles/StreetByMorning.json',
'assets/lottiefiles/___.json',
'assets/lottiefiles/a_mountain.json',
'assets/lottiefiles/accept_arrows.json',
'assets/lottiefiles/airbnb.json',
'assets/lottiefiles/android_fingerprint.json',
'assets/lottiefiles/angel.zip',
'assets/lottiefiles/anima.json',
'assets/lottiefiles/animated_graph.json',
'assets/lottiefiles/animated_laptop_.json',
'assets/lottiefiles/animated_logo.json',
'assets/lottiefiles/atm_link.json',
'assets/lottiefiles/autoconnect_loading.json',
'assets/lottiefiles/ball_&_map.zip',
'assets/lottiefiles/banner_animation.json',
'assets/lottiefiles/bb8.json',
'assets/lottiefiles/bell.json',
'assets/lottiefiles/birds.json',
'assets/lottiefiles/bitcoin_to_the_moon.json',
'assets/lottiefiles/blood_transfusion_kawaii.json',
'assets/lottiefiles/bomb.json',
'assets/lottiefiles/books.json',
'assets/lottiefiles/bootymovin.json',
'assets/lottiefiles/bounching_ball.json',
'assets/lottiefiles/brain__.json',
'assets/lottiefiles/browser.json',
'assets/lottiefiles/building_evolution_animation.json',
'assets/lottiefiles/camera.json',
'assets/lottiefiles/camptravel.zip',
'assets/lottiefiles/cancel_button.json',
'assets/lottiefiles/cash.json',
'assets/lottiefiles/change_to_search_bar.json',
'assets/lottiefiles/check_pop.json',
'assets/lottiefiles/chinese.json',
'assets/lottiefiles/clock.json',
'assets/lottiefiles/cloud_disconnection.json',
'assets/lottiefiles/code_invite_success.json',
'assets/lottiefiles/coding_ape.json',
'assets/lottiefiles/coinfall.json',
'assets/lottiefiles/colorline.json',
'assets/lottiefiles/confusion.json',
'assets/lottiefiles/construction_site.json',
'assets/lottiefiles/cooking_app.json',
'assets/lottiefiles/countdown.json',
'assets/lottiefiles/credit_card.json',
'assets/lottiefiles/credit_level.json',
'assets/lottiefiles/cube_loader.json',
'assets/lottiefiles/cubo_livre.json',
'assets/lottiefiles/curly_hair_character_loop.json',
'assets/lottiefiles/cycle_animation.json',
'assets/lottiefiles/day_night_cycle.json',
'assets/lottiefiles/day_of_the_dead.json',
'assets/lottiefiles/deadpool.json',
'assets/lottiefiles/delivery_van.json',
'assets/lottiefiles/developer-animation.zip',
'assets/lottiefiles/dna_loader.json',
'assets/lottiefiles/dog.json',
'assets/lottiefiles/done.json',
'assets/lottiefiles/download copy.json',
'assets/lottiefiles/download.json',
'assets/lottiefiles/downloader.json',
'assets/lottiefiles/drop.json',
'assets/lottiefiles/drop_to_refresh.json',
'assets/lottiefiles/edited-landscape.json',
'assets/lottiefiles/elephant_trunk_swing.json',
'assets/lottiefiles/emoji_shock.json',
'assets/lottiefiles/emoji_tongue.json',
'assets/lottiefiles/emoji_wink.json',
'assets/lottiefiles/empty_status.json',
'assets/lottiefiles/estimate.json',
'assets/lottiefiles/fab_animate.json',
'assets/lottiefiles/fabulous_onboarding_animation.json',
'assets/lottiefiles/favourite_app_icon.json',
'assets/lottiefiles/file_error.json',
'assets/lottiefiles/finance_animation.json',
'assets/lottiefiles/fingerprint_scanner.json',
'assets/lottiefiles/finish,done.json',
'assets/lottiefiles/fish.json',
'assets/lottiefiles/flag_of_mexico.json',
'assets/lottiefiles/flow.json',
'assets/lottiefiles/frog.json',
'assets/lottiefiles/funky_chicken.json',
'assets/lottiefiles/gaming_pad.json',
'assets/lottiefiles/gears.json',
'assets/lottiefiles/geometry.zip',
'assets/lottiefiles/glow_loading.json',
'assets/lottiefiles/gradient_animated_background.json',
'assets/lottiefiles/happy birthday.json',
'assets/lottiefiles/hardware.json',
'assets/lottiefiles/hint_01.json',
'assets/lottiefiles/im_thirsty.json',
'assets/lottiefiles/immiguide_.json',
'assets/lottiefiles/in-app_purchasing.json',
'assets/lottiefiles/india.json',
'assets/lottiefiles/infinite_rainbow.json',
'assets/lottiefiles/intelia_logo_animation.json',
'assets/lottiefiles/iphone_x_loading.json',
'assets/lottiefiles/jojo_the_bird.json',
'assets/lottiefiles/jolly_walker.json',
'assets/lottiefiles/judgement.json',
'assets/lottiefiles/kod.io_logo_reveal.json',
'assets/lottiefiles/la_calavera.json',
'assets/lottiefiles/landing_page.json',
'assets/lottiefiles/lego_loader.json',
'assets/lottiefiles/light.json',
'assets/lottiefiles/lightsaber.json',
'assets/lottiefiles/little_girl_jumping_-_loader.json',
'assets/lottiefiles/loading.json',
'assets/lottiefiles/loading_copy.json',
'assets/lottiefiles/loading_disc.json',
'assets/lottiefiles/loading_semicircle.json',
'assets/lottiefiles/location.json',
'assets/lottiefiles/location_marker.json',
'assets/lottiefiles/location_pin.json',
'assets/lottiefiles/lottie_logo_1.json',
'assets/lottiefiles/lottiepreview_qr.json',
'assets/lottiefiles/mailsent.json',
'assets/lottiefiles/man_and_pay_with_credit_card.json',
'assets/lottiefiles/map_animation.json',
'assets/lottiefiles/material loading.json',
'assets/lottiefiles/material_loader.json',
'assets/lottiefiles/material_loading_2.json',
'assets/lottiefiles/material_wave_loading.json',
'assets/lottiefiles/finish,done.json',
'assets/lottiefiles/rocket.json',
'assets/lottiefiles/chinese.json',
'assets/lottiefiles/cubo_livre.json',
'assets/lottiefiles/slack_app_loader.json',
'assets/lottiefiles/no_internet_connection.json',
'assets/lottiefiles/moving_eye.json',
'assets/lottiefiles/downloader.json',
'assets/lottiefiles/poo_loader.json',
'assets/lottiefiles/airbnb.json',
'assets/lottiefiles/phonological.json',
'assets/lottiefiles/camptravel.zip',
'assets/lottiefiles/bounching_ball.json',
'assets/lottiefiles/walking.json',
'assets/lottiefiles/coding_ape.json',
'assets/lottiefiles/clock.json',
'assets/lottiefiles/timer_(3_second_loop).json',
'assets/lottiefiles/file_error.json',
'assets/lottiefiles/android_fingerprint.json',
'assets/lottiefiles/patient_successfully_added.json',
'assets/lottiefiles/toggle_switch.json',
'assets/lottiefiles/notification_request.json',
'assets/lottiefiles/loading disc.json',
'assets/lottiefiles/tractor_animation.json',
'assets/lottiefiles/Plane.json',
'assets/lottiefiles/retweet.json',
'assets/lottiefiles/blood_transfusion_kawaii.json',
'assets/lottiefiles/truecosmos.json',
'assets/lottiefiles/banner_animation.json',
'assets/lottiefiles/gears.json',
'assets/lottiefiles/progress_bar 2.json',
'assets/lottiefiles/flag_of_mexico.json',
'assets/lottiefiles/location_pin.json',
'assets/lottiefiles/play,_pause.json',
'assets/lottiefiles/panel2d.json',
'assets/lottiefiles/emoji_tongue.json',
'assets/lottiefiles/jolly_walker.json',
'assets/lottiefiles/switch_loop.json',
'assets/lottiefiles/intelia_logo_animation.json',
'assets/lottiefiles/credit_card.json',
'assets/lottiefiles/empty_status.json',
'assets/lottiefiles/autoconnect_loading.json',
'assets/lottiefiles/camera.json',
'assets/lottiefiles/volume_indicator.json',
'assets/lottiefiles/bell.json',
'assets/lottiefiles/colorline.json',
'assets/lottiefiles/mailsent.json',
'assets/lottiefiles/square_drop_loader.json',
'assets/lottiefiles/gradient_animated_background.json',
'assets/lottiefiles/vr_animation.json',
'assets/lottiefiles/rocksauce_title_card.json',
'assets/lottiefiles/streetby_test_loading.json',
'assets/lottiefiles/hardware.json',
'assets/lottiefiles/man_and_pay_with_credit_card.json',
'assets/lottiefiles/tractor.json',
'assets/lottiefiles/brain__.json',
'assets/lottiefiles/summer.json',
'assets/lottiefiles/passport.json',
'assets/lottiefiles/drop_to_refresh.json',
'assets/lottiefiles/penguin.json',
'assets/lottiefiles/location_marker.json',
'assets/lottiefiles/dna_loader.json',
'assets/lottiefiles/geometry.zip',
'assets/lottiefiles/pink_drink_machine.json',
'assets/lottiefiles/sensor_scan.zip',
'assets/lottiefiles/fingerprint_scanner.json',
'assets/lottiefiles/play_button.json',
'assets/lottiefiles/jojo_the_bird.json',
'assets/lottiefiles/cloud_disconnection.json',
'assets/lottiefiles/dog.json',
'assets/lottiefiles/loading.json',
'assets/lottiefiles/curly_hair_character_loop.json',
'assets/lottiefiles/india.json',
'assets/lottiefiles/anima.json',
'assets/lottiefiles/volume_shake_indicator.json',
'assets/lottiefiles/rating.json',
'assets/lottiefiles/birds.json',
'assets/lottiefiles/in-app_purchasing.json',
'assets/lottiefiles/rejection.json',
'assets/lottiefiles/judgement.json',
'assets/lottiefiles/splashy_loader.json',
'assets/lottiefiles/construction_site.json',
'assets/lottiefiles/download.json',
'assets/lottiefiles/uk.json',
'assets/lottiefiles/location.json',
'assets/lottiefiles/change_to_search_bar.json',
'assets/lottiefiles/x_pop.json',
'assets/lottiefiles/socar_logo.json',
'assets/lottiefiles/fish.json',
'assets/lottiefiles/landing_page.json',
'assets/lottiefiles/turbine.json',
'assets/lottiefiles/ofrenda.json',
'assets/lottiefiles/emoji_shock.json',
'assets/lottiefiles/sky.zip',
'assets/lottiefiles/bb8.json',
'assets/lottiefiles/powerupp_app_onboard (1).json',
'assets/lottiefiles/im_thirsty.json',
'assets/lottiefiles/permission.json',
'assets/lottiefiles/animated_logo.json',
'assets/lottiefiles/youtube_icon_reveal.json',
'assets/lottiefiles/fab_animate.json',
'assets/lottiefiles/money.json',
'assets/lottiefiles/pagado.json',
'assets/lottiefiles/servishero_loading.json',
'assets/lottiefiles/me_at_office.json',
'assets/lottiefiles/swiftkey-logo.json',
'assets/lottiefiles/favourite_app_icon.json',
'assets/lottiefiles/atm_link.json',
'assets/lottiefiles/emoji_wink.json',
'assets/lottiefiles/preloader.json',
'assets/lottiefiles/us.json',
'assets/lottiefiles/soda_loader.json',
'assets/lottiefiles/medal.json',
'assets/lottiefiles/menuButton2.json',
'assets/lottiefiles/menu_button_alt.json',
'assets/lottiefiles/mindful.json',
'assets/lottiefiles/mnemonics.json',
'assets/lottiefiles/money.json',
'assets/lottiefiles/motorcycle.json',
'assets/lottiefiles/moving bus.json',
'assets/lottiefiles/moving_eye.json',
'assets/lottiefiles/no_internet_connection.json',
'assets/lottiefiles/notification_request.json',
'assets/lottiefiles/octopus.json',
'assets/lottiefiles/ofrenda.json',
'assets/lottiefiles/on_off_settings_switch.json',
'assets/lottiefiles/pagado.json',
'assets/lottiefiles/pagination.json',
'assets/lottiefiles/panel2d.json',
'assets/lottiefiles/passport.json',
'assets/lottiefiles/patient_successfully_added.json',
'assets/lottiefiles/payme.json',
'assets/lottiefiles/peli-canon.json',
'assets/lottiefiles/pen_tool_loop.json',
'assets/lottiefiles/pencil_write.json',
'assets/lottiefiles/penguin.json',
'assets/lottiefiles/permission.json',
'assets/lottiefiles/personal_character.json',
'assets/lottiefiles/ph_onboarding_.json',
'assets/lottiefiles/phonological.json',
'assets/lottiefiles/pink_drink_machine.json',
'assets/lottiefiles/plane_to_dollar.json',
'assets/lottiefiles/play,_pause.json',
'assets/lottiefiles/play_and_like_it.json',
'assets/lottiefiles/play_button.json',
'assets/lottiefiles/playing.json',
'assets/lottiefiles/point.json',
'assets/lottiefiles/poo_loader.json',
'assets/lottiefiles/powerupp_app_onboard (1).json',
'assets/lottiefiles/powerupp_app_onboard.json',
'assets/lottiefiles/preloader.json',
'assets/lottiefiles/print.json',
'assets/lottiefiles/progress_bar 2.json',
'assets/lottiefiles/progress_bar.json',
'assets/lottiefiles/rating.json',
'assets/lottiefiles/red_pocket_pop_up.json',
'assets/lottiefiles/rejection.json',
'assets/lottiefiles/retweet.json',
'assets/lottiefiles/rocket.json',
'assets/lottiefiles/rocksauce_title_card.json',
'assets/lottiefiles/scan.json',
'assets/lottiefiles/scan_qr_code_success.json',
'assets/lottiefiles/search_button.json',
'assets/lottiefiles/security_token_roundtable.zip',
'assets/lottiefiles/sensor_scan.zip',
'assets/lottiefiles/servishero_loading.json',
'assets/lottiefiles/simple_loader.json',
'assets/lottiefiles/sky.zip',
'assets/lottiefiles/slack_app_loader.json',
'assets/lottiefiles/snowcation.json',
'assets/lottiefiles/socar_logo.json',
'assets/lottiefiles/soda_loader.json',
'assets/lottiefiles/spacehub.json',
'assets/lottiefiles/spinner loading.json',
'assets/lottiefiles/splashy_loader.json',
'assets/lottiefiles/square_drop_loader.json',
'assets/lottiefiles/star 2.json',
'assets/lottiefiles/streetby_test_loading.json',
'assets/lottiefiles/submit button.json',
'assets/lottiefiles/summer.json',
'assets/lottiefiles/sushi_and_wine.zip',
'assets/lottiefiles/swiftkey-logo.json',
'assets/lottiefiles/swipe_menu.json',
'assets/lottiefiles/swipe_right_indicator.json',
'assets/lottiefiles/switch_loop.json',
'assets/lottiefiles/the_final_frontier.json',
'assets/lottiefiles/tigerobo_demo.json',
'assets/lottiefiles/timer_(3_second_loop).json',
'assets/lottiefiles/toggle.json',
'assets/lottiefiles/toggle_switch.json',
'assets/lottiefiles/touch_id.json',
'assets/lottiefiles/tractor.json',
'assets/lottiefiles/tractor_animation.json',
'assets/lottiefiles/trail_loading.json',
'assets/lottiefiles/trophy.json',
'assets/lottiefiles/trophy_animation.zip',
'assets/lottiefiles/countdown.json',
'assets/lottiefiles/glow_loading.json',
'assets/lottiefiles/developer-animation.zip',
'assets/lottiefiles/bitcoin_to_the_moon.json',
'assets/lottiefiles/credit_level.json',
'assets/lottiefiles/medal.json',
'assets/lottiefiles/xamarin_logo_2.json',
'assets/lottiefiles/loading copy.json',
'assets/lottiefiles/done.json',
'assets/lottiefiles/plane_to_dollar.json',
'assets/lottiefiles/octopus.json',
'assets/lottiefiles/finance_animation.json',
'assets/lottiefiles/download copy.json',
'assets/lottiefiles/frog.json',
'assets/lottiefiles/yoga_carpet.json',
'assets/lottiefiles/sushi_and_wine.zip',
'assets/lottiefiles/payme.json',
'assets/lottiefiles/lego_loader.json',
'assets/lottiefiles/deadpool.json',
'assets/lottiefiles/updating_map.json',
'assets/lottiefiles/elephant_trunk_swing.json',
'assets/lottiefiles/lottie_logo_1.json',
'assets/lottiefiles/tigerobo_demo.json',
'assets/lottiefiles/100_percent.json',
'assets/lottiefiles/flow.json',
'assets/lottiefiles/hint_01.json',
'assets/lottiefiles/moving bus.json',
'assets/lottiefiles/light.json',
'assets/lottiefiles/little_girl_jumping_-_loader.json',
'assets/lottiefiles/red_pocket_pop_up.json',
'assets/lottiefiles/star 2.json',
'assets/lottiefiles/playing.json',
'assets/lottiefiles/motorcycle.json',
'assets/lottiefiles/submit button.json',
'assets/lottiefiles/infinite_rainbow.json',
'assets/lottiefiles/print.json',
'assets/lottiefiles/powerupp_app_onboard.json',
'assets/lottiefiles/cycle_animation.json',
'assets/lottiefiles/vigilance_camera.json',
'assets/lottiefiles/code_invite_success.json',
'assets/lottiefiles/walking_arrow.json',
'assets/lottiefiles/pen_tool_loop.json',
'assets/lottiefiles/mnemonics.json',
'assets/lottiefiles/bootymovin.json',
'assets/lottiefiles/happy birthday.json',
'assets/lottiefiles/books.json',
'assets/lottiefiles/angel.zip',
'assets/lottiefiles/building_evolution_animation.json',
'assets/lottiefiles/edited-landscape.json',
'assets/lottiefiles/spinner loading.json',
'assets/lottiefiles/accept_arrows.json',
'assets/lottiefiles/mindful.json',
'assets/lottiefiles/gaming_pad.json',
'assets/lottiefiles/menuButton2.json',
'assets/lottiefiles/wolf_peek.json',
'assets/lottiefiles/security_token_roundtable.zip',
'assets/lottiefiles/day_night_cycle.json',
'assets/lottiefiles/cancel_button.json',
'assets/lottiefiles/menu_button_alt.json',
'assets/lottiefiles/animated_graph.json',
'assets/lottiefiles/point.json',
'assets/lottiefiles/search_button.json',
'assets/lottiefiles/a_mountain.json',
'assets/lottiefiles/on_off_settings_switch.json',
'assets/lottiefiles/truecosmos.json',
'assets/lottiefiles/turbine.json',
'assets/lottiefiles/typing dot.json',
'assets/lottiefiles/kod.io_logo_reveal.json',
'assets/lottiefiles/___.json',
'assets/lottiefiles/animated_laptop_.json',
'assets/lottiefiles/simple_loader.json',
'assets/lottiefiles/personal_character.json',
'assets/lottiefiles/check_pop.json',
'assets/lottiefiles/xuanwheel_logo.json',
'assets/lottiefiles/lightsaber.json',
'assets/lottiefiles/peli-canon.json',
'assets/lottiefiles/map_animation.json',
'assets/lottiefiles/funky_chicken.json',
'assets/lottiefiles/ball_&_map.zip',
'assets/lottiefiles/snowcation.json',
'assets/lottiefiles/estimate.json',
'assets/lottiefiles/delivery_van.json',
'assets/lottiefiles/spacehub.json',
'assets/lottiefiles/material loading.json',
'assets/lottiefiles/swipe_right_indicator.json',
'assets/lottiefiles/pagination.json',
'assets/lottiefiles/confusion.json',
'assets/lottiefiles/coinfall.json',
'assets/lottiefiles/fabulous_onboarding_animation.json',
'assets/lottiefiles/win_result_2.json',
'assets/lottiefiles/scan.json',
'assets/lottiefiles/la_calavera.json',
'assets/lottiefiles/drop.json',
'assets/lottiefiles/scan_qr_code_success.json',
'assets/lottiefiles/loading_semicircle.json',
'assets/lottiefiles/immiguide_.json',
'assets/lottiefiles/vr_sickness.json',
'assets/lottiefiles/cash.json',
'assets/lottiefiles/ph_onboarding_.json',
'assets/lottiefiles/uk.json',
'assets/lottiefiles/updating_map.json',
'assets/lottiefiles/us.json',
'assets/lottiefiles/video_cam.json',
'assets/lottiefiles/material_loader.json',
'assets/lottiefiles/toggle.json',
'assets/lottiefiles/browser.json',
'assets/lottiefiles/day_of_the_dead.json',
'assets/lottiefiles/cube_loader.json',
'assets/lottiefiles/washing_machine.json',
'assets/lottiefiles/vigilance_camera.json',
'assets/lottiefiles/volume_indicator.json',
'assets/lottiefiles/volume_shake_indicator.json',
'assets/lottiefiles/vr_animation.json',
'assets/lottiefiles/vr_sickness.json',
'assets/lottiefiles/walking.json',
'assets/lottiefiles/walking_arrow.json',
'assets/lottiefiles/wallet recharge.json',
'assets/lottiefiles/pencil_write.json',
'assets/lottiefiles/progress_bar.json',
'assets/lottiefiles/iphone_x_loading.json',
'assets/lottiefiles/bomb.json',
'assets/lottiefiles/swipe_menu.json',
'assets/lottiefiles/trail_loading.json',
'assets/lottiefiles/StreetByMorning.json',
'assets/lottiefiles/cooking_app.json',
'assets/lottiefiles/lottiepreview_qr.json',
'assets/lottiefiles/touch_id.json',
'assets/lf20_w2Afea.json',
'assets/lottiefiles/washing_machine.json',
'assets/lottiefiles/win_result_2.json',
'assets/lottiefiles/wolf_peek.json',
'assets/lottiefiles/x_pop.json',
'assets/lottiefiles/xamarin_logo_2.json',
'assets/lottiefiles/xuanwheel_logo.json',
'assets/lottiefiles/yoga_carpet.json',
'assets/lottiefiles/youtube_icon_reveal.json',
];

View File

@ -29,6 +29,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.0"
charcode:
dependency: transitive
description:
@ -62,11 +69,25 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_colorpicker:
dependency: "direct main"
description:
name: flutter_colorpicker
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.2"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
golden_toolkit:
dependency: "direct dev"
description:
name: golden_toolkit
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.1"
image:
dependency: transitive
description:
@ -87,7 +108,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.2.1"
version: "0.3.1"
matcher:
dependency: transitive
description:
@ -176,7 +197,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.11"
version: "0.2.15"
typed_data:
dependency: transitive
description:
@ -200,3 +221,4 @@ packages:
version: "3.5.0"
sdks:
dart: ">=2.7.0 <3.0.0"
flutter: ">=1.5.4 <2.0.0"

View File

@ -10,10 +10,12 @@ dependencies:
sdk: flutter
lottie:
path: ../
flutter_colorpicker:
dev_dependencies:
flutter_test:
sdk: flutter
golden_toolkit:
dependency_overrides:
pedantic: ^1.9.0
@ -34,33 +36,25 @@ flutter:
- assets/Images/
- assets/Images/WeAccept/
# To add assets to your package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.dev/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# To add custom fonts to your package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.dev/custom-fonts/#from-packages
fonts:
- family: Comic Neue
fonts:
- asset: assets/fonts/Comic-Neue.ttf
- family: Helvetica
fonts:
- asset: assets/fonts/Helvetica.ttf
- family: Helvetica Neue
fonts:
- asset: assets/fonts/Helvetica-Neue.ttf
- family: Open Sans
fonts:
- asset: assets/fonts/Open-Sans.ttf
- family: PT Serif
fonts:
- asset: assets/fonts/PT-Serif.ttf
- family: Roboto
fonts:
- asset: assets/fonts/Roboto.ttf
- family: Noto Emoji
fonts:
- asset: assets/fonts/NotoEmoji-Regular.ttf

View File

@ -0,0 +1,293 @@
import 'dart:io';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lottie/lottie.dart';
void main() {
LottieComposition composition;
setUpAll(() async {
composition = await LottieComposition.fromBytes(
File('assets/Tests/Shapes.json').readAsBytesSync());
});
void testGolden(String description, ValueDelegate delegate,
{double progress}) async {
var screenshotName = description
.toLowerCase()
.replaceAll(RegExp('[^a-z0-9 ]'), '')
.replaceAll(' ', '_');
testWidgets(description, (tester) async {
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]),
),
);
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: LottieDelegates(values: []),
),
);
await tester.pump();
await expectLater(find.byType(Lottie),
matchesGoldenFile('goldens/dynamic_without_delegate.png'));
}
});
}
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: Offset(20, 20)),
);
testGolden(
'Transform position',
ValueDelegate.transformPosition(['Shape Layer 1', 'Rectangle'],
value: Offset(20, 20)),
);
testGolden(
'Transform position (relative)',
ValueDelegate.transformPosition(['Shape Layer 1', 'Rectangle'],
relative: 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: 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: Offset(20, 20)),
);
testGolden(
'Rectangle size',
ValueDelegate.rectangleSize(
['Shape Layer 1', 'Rectangle', 'Rectangle Path 1'],
relative: Offset(30, 40)),
);
testGolden(
'Ellipse position',
ValueDelegate.position(['Shape Layer 1', 'Ellipse', 'Ellipse Path 1'],
relative: Offset(20, 20)),
);
testGolden(
'Ellipse size',
ValueDelegate.ellipseSize(['Shape Layer 1', 'Ellipse', 'Ellipse Path 1'],
relative: 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: 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: 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: 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: Offset(2, 2)),
);
testGolden('Time remapping', ValueDelegate.timeRemap(['Circle 1'], value: 1),
progress: 0.1);
testGolden(
'Color Filter',
ValueDelegate.colorFilter(['**'],
value: ColorFilter.mode(Colors.green, BlendMode.srcATop)),
);
testGolden(
'Null Color Filter',
ValueDelegate.colorFilter(['**'], value: null),
);
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);
}
}

View File

@ -0,0 +1,29 @@
import 'dart:io';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lottie/lottie.dart';
void main() {
testWidgets('Dynamic test', (tester) async {
var composition = await LottieComposition.fromBytes(
File('assets/Tests/DynamicText.json').readAsBytesSync());
await tester.pumpWidget(
MaterialApp(
home: Lottie(
composition: composition,
animate: false,
delegates: LottieDelegates(
text: (input) => '🔥c🔥👮🏿🔥',
textStyle: (font) => TextStyle(
fontFamily: 'Roboto', fontFamilyFallback: ['Noto Emoji']),
values: []),
),
),
);
await expectLater(
find.byType(Lottie), matchesGoldenFile('goldens/dynamic_text.png'));
});
}

View File

@ -0,0 +1,7 @@
import 'dart:async';
import 'package:golden_toolkit/golden_toolkit.dart';
Future<void> main(FutureOr<void> Function() testMain) async {
await loadAppFonts();
return testMain();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -0,0 +1,58 @@
import 'dart:io';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lottie/lottie.dart';
void main() {
void testGradient(String name, ValueDelegate valueDelegate) {
testWidgets(name, (tester) async {
var composition = await LottieComposition.fromBytes(
File('assets/Tests/DynamicGradient.json').readAsBytesSync());
var animation =
AnimationController(vsync: tester, duration: composition.duration);
await tester.pumpWidget(
Lottie(
composition: composition,
controller: animation,
delegates: LottieDelegates(values: [valueDelegate]),
),
);
var screenshotName = name
.toLowerCase()
.replaceAll(RegExp('[^a-z0-9 ]'), '')
.replaceAll(' ', '_');
await expectLater(find.byType(Lottie),
matchesGoldenFile('goldens/gradients/$screenshotName.png'));
});
}
testGradient(
'Linear Gradient Fill',
ValueDelegate.gradientColor(['Linear', 'Rectangle', 'Gradient Fill'],
value: [Color(0xFFFFFF00), Color(0xFF00FF00)]));
testGradient(
'Radial Gradient Fill',
ValueDelegate.gradientColor(['Radial', 'Rectangle', 'Gradient Fill'],
value: [Color(0xFFFFFF00), Color(0xFF00FF00)]));
testGradient(
'Linear Gradient Stroke',
ValueDelegate.gradientColor(['Linear', 'Rectangle', 'Gradient Stroke'],
value: [Color(0xFFFFFF00), Color(0xFF00FF00)]));
testGradient(
'Radial Gradient Stroke',
ValueDelegate.gradientColor(['Radial', 'Rectangle', 'Gradient Stroke'],
value: [Color(0xFFFFFF00), Color(0xFF00FF00)]));
testGradient(
'Opacity Linear Gradient Fill',
ValueDelegate.opacity(['Linear', 'Rectangle', 'Gradient Fill'],
value: 50));
}

View File

@ -0,0 +1,37 @@
import 'dart:io';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lottie/lottie.dart';
import 'package:path/path.dart' as p;
import 'utils.dart';
void main() {
testWidgets('Animations with stroke', (tester) async {
var size = Size(500, 400);
tester.binding.window.physicalSizeTestValue = size;
tester.binding.window.devicePixelRatioTestValue = 1.0;
for (var asset in [
'assets/Tests/Stroke.json',
'assets/lottiefiles/loading_disc.json',
'assets/Mobilo/G.json',
'assets/lottiefiles/truecosmos.json',
'assets/lottiefiles/intelia_logo_animation.json',
'assets/lottiefiles/landing_page.json',
'assets/lottiefiles/permission.json',
'assets/lottiefiles/little_girl_jumping_-_loader.json',
'assets/lottiefiles/playing.json',
'assets/lottiefiles/win_result_2.json',
]) {
var composition =
await LottieComposition.fromBytes(File(asset).readAsBytesSync());
await tester.pumpWidget(FilmStrip(composition, size: size));
var fileName = '${p.basenameWithoutExtension(asset)}.png'.toLowerCase();
await expectLater(find.byType(FilmStrip),
matchesGoldenFile(p.join('goldens/strokes', fileName)));
}
});
}

51
example/test/utils.dart Normal file
View File

@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
class FilmStrip extends StatelessWidget {
final LottieComposition composition;
final Size size;
const FilmStrip(this.composition, {Key key, @required this.size})
: super(key: key);
@override
Widget build(BuildContext context) {
return CustomPaint(
size: size,
painter: _CustomerPainter(composition),
);
}
}
class _CustomerPainter extends CustomPainter {
static const _columns = 5;
final LottieComposition composition;
_CustomerPainter(this.composition);
@override
void paint(Canvas canvas, Size size) {
var thumbSize = Size(size.width / _columns, size.width / _columns);
var drawable = LottieDrawable(composition);
var index = 0;
for (var progress = 0.0; progress <= 1; progress += 0.05) {
var x = index % _columns;
var y = index ~/ _columns;
var rect = Offset(x * thumbSize.width, y.toDouble() * thumbSize.height) &
thumbSize;
drawable
..setProgress(progress)
..draw(canvas, rect);
++index;
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}

View File

@ -1,12 +1,9 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter_test/flutter_test.dart';
import 'package:lottie_example/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {});
testWidgets('Main sample', (tester) async {
await tester.pumpWidget(App());
await tester.pump();
});
}

View File

@ -4,10 +4,14 @@ void main() {
var buffer = StringBuffer();
buffer.writeln('// Generated from tool/generate_file_list.dart');
buffer.writeln('final files = [');
for (var file in Directory('assets')
var allFiles = Directory('assets')
.listSync(recursive: true)
.whereType<File>()
.where((f) => f.path.endsWith('.json') || f.path.endsWith('.zip'))) {
.where((f) => f.path.endsWith('.json') || f.path.endsWith('.zip'))
.toList();
allFiles.sort((a, b) => a.path.compareTo(b.path));
for (var file in allFiles) {
buffer.writeln(" '${file.path}',");
}
buffer.writeln('];');

View File

@ -1,6 +1,8 @@
export 'src/composition.dart' show LottieComposition;
export 'src/lottie.dart' show Lottie;
export 'src/lottie_builder.dart' show LottieBuilder;
export 'src/lottie_drawable.dart' show LottieDrawable;
export 'src/lottie_delegates.dart' show LottieDelegates;
export 'src/lottie_drawable.dart' show LottieDrawable, LottieFontStyle;
export 'src/lottie_image_asset.dart' show LottieImageAsset;
export 'src/raw_lottie.dart' show RawLottie;
export 'src/value_delegate.dart' show ValueDelegate;

View File

@ -11,6 +11,7 @@ import '../../model/content/shape_trim_path.dart';
import '../../model/key_path.dart';
import '../../model/layer/base_layer.dart';
import '../../utils.dart';
import '../../utils/dash_path.dart';
import '../../utils/misc.dart';
import '../../utils/utils.dart';
import '../../value/lottie_value_callback.dart';
@ -132,7 +133,6 @@ abstract class BaseStrokeContent
L.endSection('StrokeContent#draw');
return;
}
_applyDashPatternIfNeeded(parentMatrix);
if (_colorFilterAnimation != null) {
paint.colorFilter = _colorFilterAnimation.value;
@ -152,7 +152,7 @@ abstract class BaseStrokeContent
}
L.endSection('StrokeContent#buildPath');
L.beginSection('StrokeContent#drawPath');
canvas.drawPath(_path, paint);
canvas.drawPath(_withDashPattern(_path, parentMatrix), paint);
L.endSection('StrokeContent#drawPath');
}
}
@ -199,13 +199,13 @@ abstract class BaseStrokeContent
}
var endValue = min((endLength - totalLength) / length, 1).toDouble();
Utils.applyTrimPathIfNeeded(_trimPathPath, startValue, endValue, 0.0);
canvas.drawPath(_trimPathPath, paint);
canvas.drawPath(_withDashPattern(_trimPathPath, parentMatrix), paint);
} else if (currentLength + length < startLength ||
currentLength > endLength) {
// Do nothing
} else if (currentLength + length <= endLength &&
startLength < currentLength) {
canvas.drawPath(_trimPathPath, paint);
canvas.drawPath(_withDashPattern(_trimPathPath, parentMatrix), paint);
} else {
double startValue;
if (startLength < currentLength) {
@ -220,7 +220,7 @@ abstract class BaseStrokeContent
endValue = (endLength - currentLength) / length;
}
Utils.applyTrimPathIfNeeded(_trimPathPath, startValue, endValue, 0);
canvas.drawPath(_trimPathPath, paint);
canvas.drawPath(_withDashPattern(_trimPathPath, parentMatrix), paint);
}
currentLength += length;
}
@ -250,11 +250,11 @@ abstract class BaseStrokeContent
return bounds;
}
void _applyDashPatternIfNeeded(Matrix4 parentMatrix) {
Path _withDashPattern(Path path, Matrix4 parentMatrix) {
L.beginSection('StrokeContent#applyDashPattern');
if (_dashPatternAnimations.isEmpty) {
L.endSection('StrokeContent#applyDashPattern');
return;
return path;
}
var scale = parentMatrix.getScale();
@ -275,12 +275,12 @@ abstract class BaseStrokeContent
}
_dashPatternValues[i] *= scale;
}
//TODO(xha): implement DashPathEffect with https://github.com/dnfield/flutter_path_drawing/blob/master/lib/src/dash_path.dart
// var offset = _dashPatternOffsetAnimation == null
// ? 0.0
// : _dashPatternOffsetAnimation.value * scale;
//paint.setPathEffect(DashPathEffect(_dashPatternValues, offset));
var newPath =
dashPath(path, dashArray: CircularIntervalList(_dashPatternValues));
L.endSection('StrokeContent#applyDashPattern');
return newPath;
}
@override

View File

@ -1,5 +1,4 @@
import 'dart:ui';
import 'package:flutter/painting.dart';
import 'package:vector_math/vector_math_64.dart';
import '../../l.dart';
import '../../lottie_drawable.dart';
@ -24,8 +23,8 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
static final int _cacheStepsMs = 32;
final BaseLayer layer;
final GradientFill _fill;
final _linearGradientCache = <int, LinearGradient>{};
final _radialGradientCache = <int, RadialGradient>{};
final _linearGradientCache = <int, Gradient>{};
final _radialGradientCache = <int, Gradient>{};
final _path = Path();
final _paint = Paint();
final _paths = <PathContent>[];
@ -90,20 +89,14 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
matrix4: parentMatrix.storage);
}
var boundsRect = _path.getBounds();
Gradient gradient;
if (_fill.gradientType == GradientType.linear) {
gradient = _getLinearGradient();
gradient = _getLinearGradient(parentMatrix);
} else {
gradient = _getRadialGradient();
gradient = _getRadialGradient(parentMatrix);
}
//TODO(xha)
//gradient.setLocalMatrix(parentMatrix);
//TODO(xha): cache the shader
_paint.shader = gradient.createShader(boundsRect);
_paint.shader = gradient;
if (_colorFilterAnimation != null) {
_paint.colorFilter = _colorFilterAnimation.value;
@ -131,8 +124,8 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
outBounds.right + 1, outBounds.bottom + 1);
}
LinearGradient _getLinearGradient() {
var gradientHash = getGradientHash();
Gradient _getLinearGradient(Matrix4 parentMatrix) {
var gradientHash = _getGradientHash(parentMatrix);
var gradient = _linearGradientCache[gradientHash];
if (gradient != null) {
return gradient;
@ -142,17 +135,14 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
var gradientColor = _colorAnimation.value;
var colors = _applyDynamicColorsIfNeeded(gradientColor.colors);
var positions = gradientColor.positions;
gradient = LinearGradient(
begin: Alignment(startPoint.dx, startPoint.dy),
end: Alignment(endPoint.dx, endPoint.dy),
colors: colors,
stops: positions);
gradient = Gradient.linear(startPoint, endPoint, colors, positions,
TileMode.clamp, parentMatrix.storage);
_linearGradientCache[gradientHash] = gradient;
return gradient;
}
RadialGradient _getRadialGradient() {
var gradientHash = getGradientHash();
Gradient _getRadialGradient(Matrix4 parentMatrix) {
var gradientHash = _getGradientHash(parentMatrix);
var gradient = _radialGradientCache[gradientHash];
if (gradient != null) {
return gradient;
@ -166,17 +156,17 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
var y0 = startPoint.dy;
var x1 = endPoint.dx;
var y1 = endPoint.dy;
var r = hypot(x1 - x0, y1 - y0).toDouble();
if (r <= 0) {
r = 0.001;
var radius = hypot(x1 - x0, y1 - y0).toDouble();
if (radius <= 0) {
radius = 0.001;
}
gradient = RadialGradient(
center: Alignment(x0, y0), radius: r, colors: colors, stops: positions);
gradient = Gradient.radial(startPoint, radius, colors, positions,
TileMode.clamp, parentMatrix.storage);
_radialGradientCache[gradientHash] = gradient;
return gradient;
}
int getGradientHash() {
int _getGradientHash(Matrix4 parentMatrix) {
var startPointProgress =
(_startPointAnimation.progress * _cacheSteps).round();
var endPointProgress = (_endPointAnimation.progress * _cacheSteps).round();
@ -191,6 +181,7 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
if (colorProgress != 0) {
hash = hash * 31 * colorProgress;
}
hash *= 31 * parentMatrix.hashCode;
return hash;
}

View File

@ -1,5 +1,4 @@
import 'dart:ui';
import 'package:flutter/painting.dart';
import 'package:vector_math/vector_math_64.dart';
import '../../lottie_drawable.dart';
import '../../lottie_property.dart';
@ -21,8 +20,8 @@ class GradientStrokeContent extends BaseStrokeContent {
@override
final String name;
final bool _hidden;
final _linearGradientCache = <int, LinearGradient>{};
final _radialGradientCache = <int, RadialGradient>{};
final _linearGradientCache = <int, Gradient>{};
final _radialGradientCache = <int, Gradient>{};
final GradientType _type;
final int _cacheSteps;
@ -66,25 +65,21 @@ class GradientStrokeContent extends BaseStrokeContent {
if (_hidden) {
return;
}
var boundsRect = getBounds(parentMatrix, applyParents: false);
Gradient gradient;
if (_type == GradientType.linear) {
gradient = _getLinearGradient();
gradient = _getLinearGradient(parentMatrix);
} else {
gradient = _getRadialGradient();
gradient = _getRadialGradient(parentMatrix);
}
//TODO(xha): transform the gradient with the matrix.
//shader.setLocalMatrix(parentMatrix);
//TODO(xha): cache the shader
paint.shader = gradient.createShader(boundsRect);
paint.shader = gradient;
super.draw(canvas, size, parentMatrix, parentAlpha: parentAlpha);
}
LinearGradient _getLinearGradient() {
var gradientHash = _getGradientHash();
Gradient _getLinearGradient(Matrix4 parentMatrix) {
var gradientHash = _getGradientHash(parentMatrix);
var gradient = _linearGradientCache[gradientHash];
if (gradient != null) {
return gradient;
@ -94,21 +89,15 @@ class GradientStrokeContent extends BaseStrokeContent {
var gradientColor = _colorAnimation.value;
var colors = _applyDynamicColorsIfNeeded(gradientColor.colors);
var positions = gradientColor.positions;
var x0 = startPoint.dx;
var y0 = startPoint.dy;
var x1 = endPoint.dx;
var y1 = endPoint.dy;
gradient = LinearGradient(
begin: Alignment(x0, y0),
end: Alignment(x1, y1),
colors: colors,
stops: positions);
gradient = Gradient.linear(startPoint, endPoint, colors, positions,
TileMode.clamp, parentMatrix.storage);
_linearGradientCache[gradientHash] = gradient;
return gradient;
}
RadialGradient _getRadialGradient() {
var gradientHash = _getGradientHash();
Gradient _getRadialGradient(Matrix4 parentMatrix) {
var gradientHash = _getGradientHash(parentMatrix);
var gradient = _radialGradientCache[gradientHash];
if (gradient != null) {
return gradient;
@ -122,14 +111,17 @@ class GradientStrokeContent extends BaseStrokeContent {
var y0 = startPoint.dy;
var x1 = endPoint.dx;
var y1 = endPoint.dy;
var r = hypot(x1 - x0, y1 - y0).toDouble();
gradient = RadialGradient(
center: Alignment(x0, y0), radius: r, colors: colors, stops: positions);
var radius = hypot(x1 - x0, y1 - y0).toDouble();
gradient = Gradient.radial(startPoint, radius, colors, positions,
TileMode.clamp, parentMatrix.storage);
_radialGradientCache[gradientHash] = gradient;
return gradient;
}
int _getGradientHash() {
//TODO(xha): cache the shader based on the input parameters and not the animation
// progress.
// At first, log when there is too many cache miss.
int _getGradientHash(Matrix4 parentMatrix) {
var startPointProgress =
(_startPointAnimation.progress * _cacheSteps).round();
var endPointProgress = (_endPointAnimation.progress * _cacheSteps).round();
@ -144,6 +136,7 @@ class GradientStrokeContent extends BaseStrokeContent {
if (colorProgress != 0) {
hash = hash * 31 * colorProgress;
}
hash *= 31 * parentMatrix.hashCode;
return hash;
}

View File

@ -1,32 +0,0 @@
import '../../value/keyframe.dart';
import '../../value/scale_xy.dart';
import 'keyframe_animation.dart';
class ScaleKeyframeAnimation extends KeyframeAnimation<ScaleXY> {
ScaleKeyframeAnimation(List<Keyframe<ScaleXY>> keyframes) : super(keyframes);
@override
ScaleXY getValue(Keyframe<ScaleXY> keyframe, double keyframeProgress) {
if (keyframe.startValue == null || keyframe.endValue == null) {
throw StateError('Missing values for keyframe.');
}
var startTransform = keyframe.startValue;
var endTransform = keyframe.endValue;
if (valueCallback != null) {
var value = valueCallback.getValueInternal(
keyframe.startFrame,
keyframe.endFrame,
startTransform,
endTransform,
keyframeProgress,
getLinearCurrentKeyframeProgress(),
progress);
if (value != null) {
return value;
}
}
return ScaleXY.lerp(startTransform, endTransform, keyframeProgress);
}
}

View File

@ -7,7 +7,6 @@ import '../../model/layer/base_layer.dart';
import '../../utils.dart';
import '../../value/keyframe.dart';
import '../../value/lottie_value_callback.dart';
import '../../value/scale_xy.dart';
import 'base_keyframe_animation.dart';
import 'double_keyframe_animation.dart';
import 'value_callback_keyframe_animation.dart';
@ -36,8 +35,8 @@ class TransformKeyframeAnimation {
final Matrix4 _skewMatrix3;
BaseKeyframeAnimation<Offset, Offset> /*?*/ _anchorPoint;
BaseKeyframeAnimation<dynamic, Offset> /*?*/ _position;
BaseKeyframeAnimation<ScaleXY, ScaleXY> /*?*/ _scale;
BaseKeyframeAnimation<Offset, Offset> /*?*/ _position;
BaseKeyframeAnimation<Offset, Offset> /*?*/ _scale;
BaseKeyframeAnimation<double, double> /*?*/ _rotation;
DoubleKeyframeAnimation /*?*/ _skew;
DoubleKeyframeAnimation /*?*/ _skewAngle;
@ -45,12 +44,11 @@ class TransformKeyframeAnimation {
BaseKeyframeAnimation<int, int> /*?*/ _opacity;
BaseKeyframeAnimation<int, int> /*?*/ get opacity => _opacity;
BaseKeyframeAnimation<dynamic, double> /*?*/ _startOpacity;
BaseKeyframeAnimation<dynamic, double> /*?*/ get startOpacity =>
_startOpacity;
BaseKeyframeAnimation<double, double> /*?*/ _startOpacity;
BaseKeyframeAnimation<double, double> /*?*/ get startOpacity => _startOpacity;
BaseKeyframeAnimation<dynamic, double> /*?*/ _endOpacity;
BaseKeyframeAnimation<dynamic, double> /*?*/ get endOpacity => _endOpacity;
BaseKeyframeAnimation<double, double> /*?*/ _endOpacity;
BaseKeyframeAnimation<double, double> /*?*/ get endOpacity => _endOpacity;
void addAnimationsToLayer(BaseLayer layer) {
layer.addAnimation(_opacity);
@ -141,8 +139,8 @@ class TransformKeyframeAnimation {
if (_scale != null) {
final scale = _scale.value;
if (scale.x != 1 || scale.y != 1) {
_matrix.scale(scale.x, scale.y);
if (scale.dx != 1 || scale.dy != 1) {
_matrix.scale(scale.dx, scale.dy);
}
}
@ -169,7 +167,7 @@ class TransformKeyframeAnimation {
}
if (scale != null) {
_matrix.scale(scale.x, scale.y);
_matrix.scale(scale.dx, scale.dy);
}
if (rotation != null) {
@ -200,9 +198,9 @@ class TransformKeyframeAnimation {
} else if (property == LottieProperty.transformScale) {
if (_scale == null) {
_scale = ValueCallbackKeyframeAnimation(
callback as LottieValueCallback<ScaleXY>, ScaleXY.one());
callback as LottieValueCallback<Offset>, Offset(1, 1));
} else {
_scale.setValueCallback(callback as LottieValueCallback<ScaleXY>);
_scale.setValueCallback(callback as LottieValueCallback<Offset>);
}
} else if (property == LottieProperty.transformRotation) {
if (_rotation == null) {

Some files were not shown because too many files have changed in this diff Show More