Compare commits

..

16 Commits

Author SHA1 Message Date
9e9de6d5b6 Bring some latest fixes (#307)
- Fix gradient interpolation for opacity stops beyond the last color
stop
- Add color value callback to solid layer
2023-10-20 15:50:31 +02:00
f19e86d644 Bump actions/checkout from 2 to 4 (#301) 2023-09-12 10:19:54 +02:00
ab9b5833c3 Support loading fonts from zip (#300)
Fixes #299
2023-09-12 10:12:50 +02:00
fe0032a6c2 Auto publish: use XDG_CONFIG_HOME 2023-08-08 12:29:50 +02:00
b0bc35196e Auto publish: update credentials location 2023-08-08 12:20:18 +02:00
0600c44384 Accept List<int> in LottieComposition.fromBytes (#292) 2023-08-08 11:17:12 +02:00
8a9ef53c63 v2.5 2023-07-17 22:08:46 +02:00
6ffeaa603f Allow shape to be null (#291) 2023-07-17 22:06:30 +02:00
08e629adaa Fix TextLayer opacity calculation (#285) 2023-07-17 20:17:35 +02:00
bf3118b4cf Add layer-level opacity option to LottieOptions (#286) 2023-06-16 15:17:07 +02:00
434ae88aa8 Revert Setup github publishing
It doesn't work for flutter packages
2023-06-02 21:43:14 +02:00
6b752d829c Setup github publishing 2023-06-02 21:38:17 +02:00
124ba6997b Allow RoundedCorners name to be null (#283)
Fixes
https://github.com/xvrh/lottie-flutter/issues/270#issuecomment-1573958860
2023-06-02 21:28:52 +02:00
fdc4018f57 Add an example on how to cache animation as List<Image> (#282) 2023-06-02 13:45:22 +02:00
b61ea14116 Upgrade to Flutter 3.10 & update lints (#280) 2023-05-10 23:09:40 +02:00
9c266bb98b Fix bitwise comparaison on web (#274)
Fixes #273
2023-04-06 16:07:37 +02:00
557 changed files with 23128 additions and 736 deletions

9
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,9 @@
# Dependabot configuration file.
# See https://docs.github.com/en/code-security/dependabot/dependabot-version-updates
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@ -11,9 +11,9 @@ jobs:
strategy:
matrix:
flutter: ['stable']
runs-on: macos-latest
runs-on: macos-13
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: ${{ matrix.flutter }}
@ -37,7 +37,7 @@ jobs:
name: Check that the web version can compile
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: 'stable'

View File

@ -7,23 +7,22 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
- run: flutter pub get
- run: flutter pub run tool/publish/comment_dependency_overrides.dart
- run: flutter pub get
- run: flutter pub run tool/publish/check_version.dart ${GITHUB_REF}
- name: Setup credentials
run: |
cat <<EOF > $PUB_CACHE/credentials.json
mkdir -p $XDG_CONFIG_HOME/dart
cat <<EOF > $XDG_CONFIG_HOME/dart/pub-credentials.json
{
"accessToken":"${{ secrets.OAUTH_ACCESS_TOKEN }}",
"refreshToken":"${{ secrets.OAUTH_REFRESH_TOKEN }}",
"tokenEndpoint":"https://accounts.google.com/o/oauth2/token",
"scopes": [ "openid", "https://www.googleapis.com/auth/userinfo.email" ],
"expiration": 1580681402856
"expiration": 1691492965565
}
EOF
- name: Publish package

View File

@ -1,3 +1,24 @@
## 2.7.0
- Support loading Fonts from a zip file
- Fix a bug in Text with strokes
- Fix gradient interpolation for opacity stops beyond the last color stop
- Add color value callback to solid layer
## 2.6.0
- Accept `List<int>` instead of `Uint8List` in `LottieComposition.fromBytes`
- Stroke line cap defaults to butt instead of square
## 2.5.0
- Add layer-level opacity option to LottieOptions
- Fix TextLayer opacity calculation
## 2.4.0
- Require minimum Dart 3.0.0 and Flutter 3.10.0
- Fix a parsing bug when the name property in RoundedCorner was null
## 2.3.2
- Fix a bug when running on the web due to [bitwise operations difference](https://dart.dev/guides/language/numbers#bitwise-operations).
## 2.3.1
- Fix an assertion for null `ShapeTrimPathType.type`.

View File

@ -1,33 +1,59 @@
include: package:flutter_lints/flutter.yaml
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
language:
strict-casts: true
strict-inference: true
linter:
rules:
avoid_print: false
always_declare_return_types: true
avoid_bool_literals_in_conditional_expressions: true
avoid_double_and_int_checks: true
avoid_dynamic_calls: true
avoid_equals_and_hash_code_on_mutable_classes: true
avoid_escaping_inner_quotes: true
avoid_final_parameters: true
avoid_function_literals_in_foreach_calls: true
avoid_js_rounded_ints: true
avoid_positional_boolean_parameters: true
avoid_redundant_argument_values: true
avoid_returning_null_for_future: true
avoid_setters_without_getters: true
avoid_type_to_string: true
avoid_unused_constructor_parameters: true
cancel_subscriptions: true
cast_nullable_to_non_nullable: true
close_sinks: true
collection_methods_unrelated_type: true
combinators_ordering: true
conditional_uri_does_not_exist: true
dangling_library_doc_comments: true
deprecated_consistency: true
implicit_reopen: true
invalid_case_patterns: true
leading_newlines_in_multiline_strings: true
library_annotations: true
no_adjacent_strings_in_list: true
no_default_cases: true
noop_primitive_operations: true
omit_local_variable_types: true
only_throw_errors: true
prefer_if_elements_to_conditional_expressions: true
prefer_relative_imports: true
prefer_single_quotes: true
sort_child_properties_last: true
sort_pub_dependencies: true
test_types_in_equals: true
unawaited_futures: true
unnecessary_breaks: true
unnecessary_library_directive: true
unnecessary_parenthesis: true
unnecessary_statements: true
unnecessary_to_list_in_spreads: true
unsafe_html: true
use_enums: true
use_if_null_to_convert_nulls_to_bools: true
use_named_constants: true
use_raw_strings: true
use_super_parameters: true

View File

@ -0,0 +1,441 @@
{
"v": "4.8.0",
"meta": {
"g": "LottieFiles AE 3.1.1",
"a": "",
"k": "",
"d": "",
"tc": ""
},
"fr": 30,
"ip": 0,
"op": 151,
"w": 430,
"h": 932,
"nm": "Sticker Unpack",
"ddd": 1,
"assets": [
{
"id": "comp_0",
"layers": [
]
}
],
"layers": [
{
"ddd": 1,
"ind": 1,
"ty": 0,
"nm": "Pc_Sticker Pack",
"refId": "comp_0",
"sr": 1,
"ks": {
"o": {
"a": 0,
"k": 100,
"ix": 11
},
"rx": {
"a": 1,
"k": [
{
"i": {
"x": [
0.421
],
"y": [
1
]
},
"o": {
"x": [
0.55
],
"y": [
0
]
},
"t": 1,
"s": [
0
]
},
{
"i": {
"x": [
0.985
],
"y": [
0.168
]
},
"o": {
"x": [
0.857
],
"y": [
0
]
},
"t": 21,
"s": [
-1.9
]
},
{
"t": 41,
"s": [
24.3
]
}
],
"ix": 8
},
"ry": {
"a": 1,
"k": [
{
"i": {
"x": [
0.421
],
"y": [
1
]
},
"o": {
"x": [
0.55
],
"y": [
0
]
},
"t": 1,
"s": [
0
]
},
{
"i": {
"x": [
0.985
],
"y": [
-0.28
]
},
"o": {
"x": [
0.857
],
"y": [
0
]
},
"t": 21,
"s": [
3.7
]
},
{
"t": 41,
"s": [
16
]
}
],
"ix": 9
},
"rz": {
"a": 0,
"k": 0,
"ix": 10
},
"or": {
"a": 0,
"k": [
0,
0,
0
],
"ix": 7
},
"p": {
"s": true,
"x": {
"a": 0,
"k": 215,
"ix": 3
},
"y": {
"a": 0,
"k": 466,
"ix": 4
},
"z": {
"a": 0,
"k": 0,
"ix": 5
}
},
"a": {
"a": 0,
"k": [
221,
307.5,
0
],
"ix": 1
},
"s": {
"a": 1,
"k": [
{
"i": {
"x": [
0.421,
0.421,
0.667
],
"y": [
1,
1,
1
]
},
"o": {
"x": [
0.55,
0.55,
0.333
],
"y": [
0,
0,
0
]
},
"t": 0,
"s": [
64.6,
64.6,
100
]
},
{
"i": {
"x": [
0.985,
0.985,
0.667
],
"y": [
0.192,
0.192,
1
]
},
"o": {
"x": [
0.857,
0.857,
0.333
],
"y": [
0,
0,
0
]
},
"t": 20,
"s": [
74.2,
74.2,
100
]
},
{
"t": 40,
"s": [
7,
7,
100
]
}
],
"ix": 6
}
},
"ao": 0,
"w": 442,
"h": 615,
"ip": 0,
"op": 41,
"st": 0,
"bm": 0
},
{
"ddd": 0,
"ind": 14,
"ty": 4,
"nm": "Shape Layer 2",
"parent": 1,
"sr": 1,
"ks": {
"o": {
"a": 0,
"k": 100,
"ix": 11
},
"r": {
"a": 0,
"k": 0,
"ix": 10
},
"p": {
"a": 0,
"k": [
221,
307.5,
0
],
"ix": 2
},
"a": {
"a": 0,
"k": [
0,
0,
0
],
"ix": 1
},
"s": {
"a": 0,
"k": [
538.543,
538.543,
100
],
"ix": 6
}
},
"ao": 0,
"shapes": [
{
"ty": "gr",
"it": [
{
"ty": "rc",
"d": 1,
"s": {
"a": 0,
"k": [
294,
403
],
"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": "gf",
"o": {
"a": 0,
"k": 100,
"ix": 10
},
"r": 1,
"bm": 0,
"g": {
"p": 3,
"k": {
"a": 0,
"k": [
0,
0.373,
0.024,
0.898,
0.359,
0.186,
0.012,
0.449,
0.998,
0,
0,
0,
0,
1,
0.5,
0.5,
1,
0
],
"ix": 9
}
},
"s": {
"a": 0,
"k": [
0,
0
],
"ix": 5
},
"e": {
"a": 0,
"k": [
149,
0
],
"ix": 6
},
"t": 2,
"h": {
"a": 0,
"k": 0,
"ix": 7
},
"a": {
"a": 0,
"k": 0,
"ix": 8
},
"nm": "Gradient Fill 1",
"mn": "ADBE Vector Graphic - G-Fill",
"hd": false
}
],
"nm": "Rectangle 1",
"np": 3,
"cix": 2,
"bm": 0,
"ix": 1,
"mn": "ADBE Vector Group",
"hd": false
}
],
"ip": 0,
"op": 42,
"st": 0,
"bm": 0
}
],
"markers": []
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
{"v":"5.1.20","fr":30,"ip":0,"op":100,"w":600,"h":400,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"test Outlines","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":0,"s":[100],"e":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":30,"s":[0],"e":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":50,"s":[0],"e":[100]},{"t":80}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[300,200,0],"ix":2},"a":{"a":0,"k":[400,300,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-66.274],[66.274,0],[0,66.274],[-66.274,0]],"o":[[0,66.274],[-66.274,0],[0,-66.274],[66.274,0]],"v":[[120,0],[0,120],[-120,0],[0,-120]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[488,300],"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":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-66.274],[66.274,0],[0,66.274],[-66.274,0]],"o":[[0,66.274],[-66.274,0],[0,-66.274],[66.274,0]],"v":[[120,0],[0,120],[-120,0],[0,-120]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40800000359,0.40800000359,0.40800000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[312,300],"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":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":100,"st":0,"bm":0}],"markers":[]}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"v":"5.12.1","fr":60,"ip":0,"op":120,"w":853,"h":480,"nm":"Comp 1","ddd":0,"assets":[],"fonts":{"list":[{"fName":"Pretendard-Bold","fFamily":"Pretendard","fStyle":"Bold","ascent":70.7131249997765}]},"layers":[{"ddd":0,"ind":1,"ty":5,"nm":"PASS","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[426,235.889,0],"ix":2,"l":2},"a":{"a":0,"k":[6.157,-60.098,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"t":{"d":{"k":[{"s":{"s":170,"f":"Pretendard-Bold","t":"PASS","ca":0,"j":2,"tr":49,"lh":317,"ls":0,"fc":[1,1,1],"sc":[0.941,0.941,0.941],"sw":0.00999999977648,"of":true},"t":0}]},"p":{},"m":{"g":1,"a":{"a":0,"k":[0,0],"ix":2}},"a":[{"nm":"Animator 1","s":{"t":0,"xe":{"a":0,"k":0,"ix":7},"ne":{"a":0,"k":0,"ix":8},"a":{"a":0,"k":100,"ix":4},"b":1,"rn":0,"sh":1,"sm":{"a":0,"k":100,"ix":6},"s":{"a":1,"k":[{"i":{"x":[0.205],"y":[1]},"o":{"x":[0.77],"y":[0]},"t":10,"s":[0]},{"t":47,"s":[100]}],"ix":1},"r":1},"a":{"p":{"a":0,"k":[0,88,0],"ix":2},"o":{"a":0,"k":0,"ix":9},"t":{"a":0,"k":-66,"ix":89}}},{"nm":"Animator 2","s":{"t":0,"xe":{"a":0,"k":0,"ix":7},"ne":{"a":0,"k":0,"ix":8},"a":{"a":0,"k":100,"ix":4},"b":1,"rn":0,"sh":1,"sm":{"a":0,"k":100,"ix":6},"r":1},"a":{"t":{"a":1,"k":[{"i":{"x":[0.092],"y":[1]},"o":{"x":[0.887],"y":[0]},"t":46,"s":[-7]},{"t":90,"s":[4]}],"ix":89}}}]},"ip":10,"op":130,"st":10,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":1,"nm":"Dark Turquoise Solid 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[426.5,240,0],"ix":2,"l":2},"a":{"a":0,"k":[75,50,0],"ix":1,"l":2},"s":{"a":0,"k":[568.667,480,100],"ix":6,"l":2}},"ao":0,"sw":150,"sh":100,"sc":"#003626","ip":0,"op":120,"st":0,"bm":0}],"markers":[],"props":{},"chars":[{"ch":"P","size":170,"style":"Bold","w":62.3,"data":{"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,14.16],[16.113,0],[0,0]],"o":[[0,0],[0,0],[0,0],[16.309,0],[0,-13.965],[0,0],[0,0]],"v":[[5.957,0],[20.605,0],[20.605,-23.047],[33.301,-23.047],[58.984,-46.875],[33.691,-70.703],[5.957,-70.703]],"c":true},"ix":2},"nm":"P","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,-7.031],[8.691,0]],"o":[[0,0],[0,0],[8.691,0],[0,7.129],[0,0]],"v":[[20.605,-34.863],[20.605,-58.691],[30.957,-58.691],[43.848,-46.875],[30.957,-34.863]],"c":true},"ix":2},"nm":"P","mn":"ADBE Vector Shape - Group","hd":false}],"nm":"P","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}]},"fFamily":"Pretendard"},{"ch":"A","size":170,"style":"Bold","w":71.78,"data":{"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[17.773,0],[23.145,-16.309],[48.73,-16.309],[54.004,0],[69.727,0],[45.312,-70.703],[26.465,-70.703],[1.953,0]],"c":true},"ix":2},"nm":"A","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[26.855,-27.734],[35.645,-54.785],[36.133,-54.785],[45.02,-27.734]],"c":true},"ix":2},"nm":"A","mn":"ADBE Vector Shape - Group","hd":false}],"nm":"A","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}]},"fFamily":"Pretendard"},{"ch":"S","size":170,"style":"Bold","w":62.99,"data":{"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.586,-5.566],[0,0],[15.625,0],[0,-12.891],[-11.914,-2.93],[0,0],[0,-4.785],[7.715,0],[0.488,7.129],[0,0],[-17.09,0],[0,12.988],[12.109,2.734],[0,0],[-0.098,5.078],[-7.422,0]],"o":[[0,0],[-0.195,-12.5],[-15.43,0],[0,10.352],[0,0],[7.715,1.953],[0,5.273],[-7.812,0],[0,0],[0.391,15.137],[17.188,0],[0,-11.816],[0,0],[-6.055,-1.367],[0.098,-4.688],[7.129,0]],"v":[[44.336,-50.488],[58.398,-50.488],[32.227,-71.68],[5.469,-50.293],[24.707,-31.055],[32.422,-29.199],[44.531,-20.215],[31.836,-11.328],[17.871,-22.07],[3.613,-22.07],[32.031,0.977],[59.375,-20.215],[38.184,-40.918],[31.836,-42.48],[20.508,-51.27],[32.129,-59.375]],"c":true},"ix":2},"nm":"S","mn":"ADBE Vector Shape - Group","hd":false}],"nm":"S","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}]},"fFamily":"Pretendard"}]}

Binary file not shown.

View File

@ -0,0 +1,130 @@
import 'dart:ui';
import 'package:flutter/material.dart' hide Image;
import 'package:flutter/material.dart' as material;
import 'package:lottie/lottie.dart';
/// This example shows how to cache the animation as a List<Image>.
/// After the initial cache of each frame, drawing the animation is almost free
/// in term of CPU usage.
/// The animation will run at a specific framerate (not FrameRate.max) and specific size
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Pre-load the animation for simplicity in this example
var animation = await AssetLottie('assets/AndroidWave.json').load();
// Pick a specific size for our cache.
// In a real app, we may want to defer choosing the size after an initial
// Layout (ie. using LayoutBuilder)
var cachedAnimation = CachedLottie(const Size(150, 200), animation);
runApp(_Example(
lottie: cachedAnimation,
));
}
class _Example extends StatelessWidget {
final CachedLottie lottie;
const _Example({required this.lottie});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Cache'),
),
body: ListView(
children: [
for (var i = 0; i < 20; i++)
Stack(
children: [
for (var j = 0; j < 50; j++)
Transform.translate(
offset: Offset(j.toDouble() * 20, 0),
child: CachedLottiePlayer(
lottie: lottie,
),
)
],
),
],
),
),
);
}
}
class CachedLottie {
final Size size;
final LottieComposition composition;
final List<Image?> images;
late final _drawable = LottieDrawable(composition);
CachedLottie(this.size, this.composition)
: images = List.filled(composition.durationFrames.ceil(), null);
Duration get duration => composition.duration;
Image imageAt(BuildContext context, double progress) {
var index = (images.length * progress).round() % images.length;
return images[index] ??= _takeImage(context, progress);
}
Image _takeImage(BuildContext context, double progress) {
var recorder = PictureRecorder();
var canvas = Canvas(recorder);
var devicePixelRatio = View.of(context).devicePixelRatio;
_drawable
..setProgress(progress)
..draw(canvas, Offset.zero & (size * devicePixelRatio));
var picture = recorder.endRecording();
return picture.toImageSync((size.width * devicePixelRatio).round(),
(size.height * devicePixelRatio).round());
}
}
class CachedLottiePlayer extends StatefulWidget {
final CachedLottie lottie;
final AnimationController? controller;
const CachedLottiePlayer({
super.key,
required this.lottie,
this.controller,
});
@override
State<CachedLottiePlayer> createState() => _CachedLottiePlayerState();
}
class _CachedLottiePlayerState extends State<CachedLottiePlayer>
with TickerProviderStateMixin {
late final AnimationController _autoController =
AnimationController(vsync: this, duration: widget.lottie.duration)
..repeat();
@override
Widget build(BuildContext context) {
var controller = widget.controller ?? _autoController;
return AnimatedBuilder(
animation: controller,
builder: (context, _) {
var image = widget.lottie.imageAt(context, controller.value);
return material.RawImage(
image: image,
width: widget.lottie.size.width,
height: widget.lottie.size.height,
);
},
);
}
@override
void dispose() {
_autoController.dispose();
super.dispose();
}
}

View File

@ -6,18 +6,18 @@ PODS:
DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
EXTERNAL SOURCES:
FlutterMacOS:
:path: Flutter/ephemeral
path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
SPEC CHECKSUMS:
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7
COCOAPODS: 1.11.3
COCOAPODS: 1.12.1

View File

@ -203,7 +203,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1300;
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "The Flutter Authors";
TargetAttributes = {
33CC10EC2044A3C60003C045 = {

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -5,18 +5,18 @@ packages:
dependency: transitive
description:
name: archive
sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d
sha256: "7e0d52067d05f2e0324268097ba723b71cb41ac8a6a2b24d1edf9c536b987b03"
url: "https://pub.dev"
source: hosted
version: "3.3.6"
version: "3.4.6"
async:
dependency: transitive
description:
name: async
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.10.0"
version: "2.11.0"
boolean_selector:
dependency: transitive
description:
@ -29,10 +29,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "1.3.0"
clock:
dependency: transitive
description:
@ -45,10 +45,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
url: "https://pub.dev"
source: hosted
version: "1.17.0"
version: "1.17.2"
convert:
dependency: transitive
description:
@ -61,10 +61,10 @@ packages:
dependency: transitive
description:
name: crypto
sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.2"
version: "3.0.3"
fake_async:
dependency: transitive
description:
@ -77,18 +77,10 @@ packages:
dependency: transitive
description:
name: ffi
sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
file:
dependency: transitive
description:
name: file
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
url: "https://pub.dev"
source: hosted
version: "6.1.4"
version: "2.1.0"
flutter:
dependency: "direct main"
description: flutter
@ -106,10 +98,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_lints
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
sha256: ad76540d21c066228ee3f9d1dad64a9f7e46530e8bb7c85011a88bc1fd874bc5
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "3.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -127,10 +119,10 @@ packages:
dependency: "direct main"
description:
name: http
sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482"
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
url: "https://pub.dev"
source: hosted
version: "0.13.5"
version: "1.1.0"
http_parser:
dependency: transitive
description:
@ -143,145 +135,137 @@ packages:
dependency: transitive
description:
name: js
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
version: "0.6.5"
version: "0.6.7"
lints:
dependency: transitive
description:
name: lints
sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593"
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "3.0.0"
logging:
dependency: "direct main"
description:
name: logging
sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.2.0"
lottie:
dependency: "direct main"
description:
path: ".."
relative: true
source: path
version: "2.3.1"
version: "2.7.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev"
source: hosted
version: "0.12.13"
version: "0.12.16"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
version: "0.5.0"
meta:
dependency: transitive
description:
name: meta
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.dev"
source: hosted
version: "1.8.0"
version: "1.9.1"
path:
dependency: "direct main"
description:
name: path
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev"
source: hosted
version: "1.8.2"
version: "1.8.3"
path_provider:
dependency: "direct main"
description:
name: path_provider
sha256: "04890b994ee89bfa80bf3080bfec40d5a92c5c7a785ebb02c13084a099d2b6f9"
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
url: "https://pub.dev"
source: hosted
version: "2.0.13"
version: "2.1.1"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: "7623b7d4be0f0f7d9a8b5ee6879fc13e4522d4c875ab86801dee4af32b54b83e"
sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1"
url: "https://pub.dev"
source: hosted
version: "2.0.23"
version: "2.2.0"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: eec003594f19fe2456ea965ae36b3fc967bc5005f508890aafe31fa75e41d972
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.3.1"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: "525ad5e07622d19447ad740b1ed5070031f7a5437f44355ae915ff56e986429a"
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.1.9"
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec"
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
url: "https://pub.dev"
source: hosted
version: "2.0.6"
version: "2.1.1"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: "642ddf65fde5404f83267e8459ddb4556316d3ee6d511ed193357e25caa3632d"
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.2.1"
platform:
dependency: transitive
description:
name: platform
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
version: "3.1.3"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.6"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
url: "https://pub.dev"
source: hosted
version: "3.6.2"
process:
dependency: transitive
description:
name: process
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
url: "https://pub.dev"
source: hosted
version: "4.2.4"
version: "3.7.3"
sky_engine:
dependency: transitive
description: flutter
@ -291,10 +275,10 @@ packages:
dependency: transitive
description:
name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.10.0"
stack_trace:
dependency: transitive
description:
@ -331,18 +315,18 @@ packages:
dependency: transitive
description:
name: test_api
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
url: "https://pub.dev"
source: hosted
version: "0.4.16"
version: "0.6.0"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.1"
version: "1.3.2"
vector_math:
dependency: transitive
description:
@ -351,22 +335,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
web:
dependency: transitive
description:
name: web
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
url: "https://pub.dev"
source: hosted
version: "0.1.4-beta"
win32:
dependency: transitive
description:
name: win32
sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
version: "5.0.9"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
version: "1.0.3"
sdks:
dart: ">=2.18.4 <3.0.0"
flutter: ">=3.3.0"
dart: ">=3.1.0 <4.0.0"
flutter: ">=3.13.0"

View File

@ -3,7 +3,7 @@ description: A sample app for the Lottie player
publish_to: none
environment:
sdk: ">=2.18.0 <3.0.0"
sdk: "^3.0.0"
dependencies:
flutter:

View File

@ -10,7 +10,7 @@ export 'src/options.dart' show LottieOptions;
export 'src/providers/asset_provider.dart' show AssetLottie;
export 'src/providers/file_provider.dart' show FileLottie;
export 'src/providers/load_image.dart' show LottieImageProviderFactory;
export 'src/providers/lottie_provider.dart' show LottieProvider, LottieCache;
export 'src/providers/lottie_provider.dart' show LottieCache, LottieProvider;
export 'src/providers/memory_provider.dart' show MemoryLottie;
export 'src/providers/network_provider.dart' show NetworkLottie;
export 'src/raw_lottie.dart' show RawLottie;

View File

@ -144,7 +144,7 @@ abstract class BaseStrokeContent
}
var alpha =
((parentAlpha / 255.0 * _opacityAnimation.value / 100.0) * 255).round();
paint.setAlpha(alpha.clamp(0, 255).toInt());
paint.setAlpha(alpha.clamp(0, 255));
paint.strokeWidth = _widthAnimation.value * parentMatrix.getScale();
if (paint.strokeWidth <= 0) {
// Android draws a hairline stroke for 0, After Effects doesn't.

View File

@ -58,12 +58,14 @@ class ContentGroup implements DrawingContent, PathContent, KeyPathElement {
lottieDrawable,
layer,
shapeGroup.name,
shapeGroup.hidden,
contentsFromModels(lottieDrawable, layer, shapeGroup.items),
findTransform(shapeGroup.items));
findTransform(shapeGroup.items),
hidden: shapeGroup.hidden);
ContentGroup.copy(this._lottieDrawable, BaseLayer layer, this.name,
this._hidden, this._contents, AnimatableTransform? transform) {
this._contents, AnimatableTransform? transform,
{required bool hidden})
: _hidden = hidden {
if (transform != null) {
_transformAnimation = transform.createAnimation()
..addAnimationsToLayer(layer)

View File

@ -89,7 +89,7 @@ class FillContent implements DrawingContent, KeyPathElementContent {
_paint.color = _colorAnimation.value;
var alpha =
((parentAlpha / 255.0 * _opacityAnimation.value / 100.0) * 255).round();
_paint.setAlpha(alpha.clamp(0, 255).toInt());
_paint.setAlpha(alpha.clamp(0, 255));
if (lottieDrawable.antiAliasingSuggested) {
_paint.isAntiAlias = true;
}

View File

@ -135,7 +135,7 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
var alpha =
((parentAlpha / 255.0 * _opacityAnimation.value / 100.0) * 255).round();
_paint.setAlpha(alpha.clamp(0, 255).toInt());
_paint.setAlpha(alpha.clamp(0, 255));
if (lottieDrawable.antiAliasingSuggested) {
_paint.isAntiAlias = true;
}
@ -175,8 +175,7 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
var gradientColor = _colorAnimation.value;
var colors = _applyDynamicColorsIfNeeded(gradientColor.colors);
var positions = gradientColor.positions;
gradient = Gradient.linear(
startPoint, endPoint, colors, positions, TileMode.clamp);
gradient = Gradient.linear(startPoint, endPoint, colors, positions);
_linearGradientCache[gradientHash] = gradient;
return gradient;
}
@ -200,8 +199,7 @@ class GradientFillContent implements DrawingContent, KeyPathElementContent {
if (radius <= 0) {
radius = 0.001;
}
gradient =
Gradient.radial(startPoint, radius, colors, positions, TileMode.clamp);
gradient = Gradient.radial(startPoint, radius, colors, positions);
_radialGradientCache[gradientHash] = gradient;
return gradient;
}

View File

@ -50,19 +50,14 @@ class MergePathsContent implements PathContent, GreedyContent {
switch (_mergePaths.mode) {
case MergePathsMode.merge:
_addPaths();
break;
case MergePathsMode.add:
_opFirstPathWithRest(PathOperation.union);
break;
case MergePathsMode.substract:
_opFirstPathWithRest(PathOperation.reverseDifference);
break;
case MergePathsMode.intersect:
_opFirstPathWithRest(PathOperation.intersect);
break;
case MergePathsMode.excludeIntersections:
_opFirstPathWithRest(PathOperation.xor);
break;
}
return _path;

View File

@ -108,10 +108,8 @@ class PolystarContent implements PathContent, KeyPathElementContent {
switch (_polystarShape.type) {
case PolystarShapeType.star:
_createStarPath();
break;
case PolystarShapeType.polygon:
_createPolygonPath();
break;
}
_path.close();
@ -253,7 +251,7 @@ class PolystarContent implements PathContent, KeyPathElementContent {
_path.moveTo(x, y);
currentAngle += anglePerPoint;
var numPoints = points.ceil().toDouble();
var numPoints = points.toDouble();
for (var i = 0; i < numPoints; i++) {
previousX = x;
previousY = y;

View File

@ -79,7 +79,8 @@ class RepeaterContent
newContents = newContents.reversed.toList();
_contentGroup = ContentGroup.copy(
lottieDrawable, layer, 'Repeater', _repeater.hidden, newContents, null);
lottieDrawable, layer, 'Repeater', newContents, null,
hidden: _repeater.hidden);
}
@override

View File

@ -6,6 +6,7 @@ import '../../model/content/shape_data.dart';
import '../../model/cubic_curve_data.dart';
import '../../model/layer/base_layer.dart';
import '../../utils.dart';
import '../../utils/misc.dart';
import '../keyframe/base_keyframe_animation.dart';
import 'content.dart';
import 'shape_modifier_content.dart';
@ -215,22 +216,9 @@ class RoundedCornersContent implements ShapeModifierContent {
this.shapeData = shapeData =
ShapeData(newCurves, initialPoint: Offset.zero, closed: false);
}
shapeData.setClosed(isClosed);
shapeData.isClosed = isClosed;
return shapeData;
}
/// Copied from the API 24+ AOSP source.
static int floorMod(int x, int y) {
return x - floorDiv(x, y) * y;
}
/// Copied from the API 24+ AOSP source.
static int floorDiv(int x, int y) {
var r = x ~/ y;
// if the signs are different and modulo not zero, round down
if ((x ^ y) < 0 && (r * y != x)) {
r--;
}
return r;
}
static int floorMod(int x, int y) => MiscUtils.floorModInt(x, y);
}

View File

@ -1,5 +1,6 @@
import 'dart:math';
import 'dart:typed_data';
import 'dart:ui';
import 'package:archive/archive.dart';
import 'package:flutter/widgets.dart';
import 'package:path/path.dart' as p;
@ -41,7 +42,7 @@ class LottieComposition {
name: name, imageProviderFactory: imageProviderFactory);
}
static Future<LottieComposition> fromBytes(Uint8List bytes,
static Future<LottieComposition> fromBytes(List<int> bytes,
{String? name, LottieImageProviderFactory? imageProviderFactory}) async {
Archive? archive;
if (bytes[0] == 0x50 && bytes[1] == 0x4B) {
@ -73,6 +74,14 @@ class LottieComposition {
composition, image, MemoryImage(found.content as Uint8List));
}
}
for (var font in archive.files.where((f) => f.name.endsWith('.ttf'))) {
var fileName = p.basenameWithoutExtension(font.name).toLowerCase();
var existingFont = composition.fonts.values
.firstWhereOrNull((f) => f.family.toLowerCase() == fileName);
await loadFontFromList(font.content as Uint8List,
fontFamily: existingFont?.family);
}
}
return composition;

View File

@ -302,6 +302,7 @@ class Lottie extends StatefulWidget {
/// Some options to enable/disable some feature of Lottie
/// - enableMergePaths: Enable merge path support
/// - enableApplyingOpacityToLayers: Enable layer-level opacity
final LottieOptions? options;
/// Indicate to automatically add a `RepaintBoundary` widget around the animation.

View File

@ -219,6 +219,7 @@ class LottieBuilder extends StatefulWidget {
/// Some options to enable/disable some feature of Lottie
/// - enableMergePaths: Enable merge path support
/// - enableApplyingOpacityToLayers: Enable layer-level opacity
final LottieOptions? options;
/// A builder function responsible for creating the widget that represents

View File

@ -5,12 +5,12 @@ import '../cubic_curve_data.dart';
class ShapeData {
final List<CubicCurveData> curves;
Offset _initialPoint;
bool _closed;
bool isClosed;
ShapeData(List<CubicCurveData> curves, {Offset? initialPoint, bool? closed})
: curves = curves.toList(),
_initialPoint = initialPoint ?? Offset.zero,
_closed = closed ?? false;
isClosed = closed ?? false;
ShapeData.empty() : this([]);
@ -22,17 +22,9 @@ class ShapeData {
return _initialPoint;
}
void setClosed(bool closed) {
_closed = closed;
}
bool get isClosed {
return _closed;
}
void interpolateBetween(
ShapeData shapeData1, ShapeData shapeData2, double percentage) {
_closed = shapeData1.isClosed || shapeData2.isClosed;
isClosed = shapeData1.isClosed || shapeData2.isClosed;
if (shapeData1.curves.length != shapeData2.curves.length) {
// TODO(xha): decide what to do? We don't have access to the LottieDrawble
@ -86,7 +78,7 @@ class ShapeData {
String toString() {
return 'ShapeData{'
'numCurves=${curves.length}'
'closed=$_closed'
'closed=$isClosed'
'}';
}
}

View File

@ -18,7 +18,7 @@ ui.StrokeCap lineCapTypeToPaintCap(LineCapType? cap) {
return ui.StrokeCap.round;
case LineCapType.unknown:
case null:
return ui.StrokeCap.square;
return ui.StrokeCap.butt;
}
}

View File

@ -1,7 +1,9 @@
import 'dart:ui';
import 'package:flutter/foundation.dart';
enum Justification { leftAlign, rightAlign, center }
@immutable
class DocumentData {
final String text;
final String? fontName;
@ -19,7 +21,7 @@ class DocumentData {
final Offset? boxPosition;
final Offset? boxSize;
DocumentData({
const DocumentData({
required this.text,
this.fontName,
required this.size,

View File

@ -1,5 +1,7 @@
import 'package:flutter/foundation.dart';
import 'content/shape_group.dart';
@immutable
class FontCharacter {
static int hashFor(String character, String fontFamily, String style) {
var result = character.hashCode;
@ -15,7 +17,7 @@ class FontCharacter {
final String style;
final String fontFamily;
FontCharacter(
const FontCharacter(
{required this.shapes,
required this.character,
required this.size,

View File

@ -363,7 +363,6 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
_contentPaint.setAlpha(255);
canvas.drawRect(bounds, _contentPaint);
}
break;
case MaskMode.maskModeAdd:
if (mask.isInverted) {
_applyInvertedAddMask(
@ -372,7 +371,6 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
_applyAddMask(
canvas, matrix, mask, maskAnimation, opacityAnimation);
}
break;
case MaskMode.maskModeSubstract:
if (i == 0) {
_contentPaint.color = const ui.Color(0xFF000000);
@ -385,7 +383,6 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
_applySubtractMask(
canvas, matrix, mask, maskAnimation, opacityAnimation);
}
break;
case MaskMode.maskModeIntersect:
if (mask.isInverted) {
_applyInvertedIntersectMask(
@ -394,7 +391,6 @@ abstract class BaseLayer implements DrawingContent, KeyPathElement {
_applyIntersectMask(
canvas, bounds, matrix, mask, maskAnimation, opacityAnimation);
}
break;
}
}
L.beginSection('Layer#restoreLayer');

View File

@ -50,7 +50,6 @@ class CompositionLayer extends BaseLayer {
case MatteType.add:
case MatteType.invert:
mattedLayer = layer;
break;
case MatteType.luma:
case MatteType.lumaInverted:
case MatteType.none:

View File

@ -14,6 +14,7 @@ class SolidLayer extends BaseLayer {
final Paint paint = Paint()..style = PaintingStyle.fill;
final Path path = PathFactory.create();
BaseKeyframeAnimation<ColorFilter, ColorFilter?>? _colorFilterAnimation;
BaseKeyframeAnimation<Color, Color?>? _colorAnimation;
SolidLayer(LottieDrawable lottieDrawable, Layer layerModel)
: super(lottieDrawable, layerModel) {
@ -35,6 +36,9 @@ class SolidLayer extends BaseLayer {
255.0)
.round();
paint.setAlpha(alpha);
if (_colorAnimation?.value case var color?) {
paint.color = color;
}
if (_colorFilterAnimation != null) {
paint.colorFilter = _colorFilterAnimation!.value;
}
@ -76,6 +80,14 @@ class SolidLayer extends BaseLayer {
_colorFilterAnimation = ValueCallbackKeyframeAnimation(
callback as LottieValueCallback<ColorFilter>, null);
}
} else if (property == LottieProperty.color) {
if (callback == null) {
_colorAnimation = null;
paint.color = layerModel.solidColor;
} else {
_colorAnimation = ValueCallbackKeyframeAnimation(
callback as LottieValueCallback<Color>, null);
}
}
}
}

View File

@ -100,7 +100,7 @@ class TextLayer extends BaseLayer {
canvas.save();
canvas.transform(parentMatrix.storage);
_configurePaint(documentData, parentMatrix);
_configurePaint(documentData, parentAlpha);
if (lottieDrawable.useTextGlyphs) {
_drawTextWithGlyphs(documentData, parentMatrix, font, canvas);
@ -111,7 +111,7 @@ class TextLayer extends BaseLayer {
canvas.restore();
}
void _configurePaint(DocumentData documentData, Matrix4 parentMatrix) {
void _configurePaint(DocumentData documentData, int parentAlpha) {
Color fillPaintColor;
if (_colorCallbackAnimation != null) {
fillPaintColor = _colorCallbackAnimation!.value;
@ -133,7 +133,7 @@ class TextLayer extends BaseLayer {
_strokePaint.color = strokePaintColor.withAlpha(_strokePaint.color.alpha);
var opacity = transform.opacity?.value ?? 100;
var alpha = (opacity * 255 / 100).round();
var alpha = opacity * 255 / 100 * parentAlpha ~/ 255;
_fillPaint.setAlpha(alpha);
_strokePaint.setAlpha(alpha);
@ -195,8 +195,7 @@ class TextLayer extends BaseLayer {
void _drawGlyphTextLine(Characters text, DocumentData documentData, Font font,
Canvas canvas, double parentScale, double fontScale, double tracking) {
for (var c in text) {
var characterHash =
FontCharacter.hashFor(c.toString(), font.family, font.style);
var characterHash = FontCharacter.hashFor(c, font.family, font.style);
var character = _composition.characters[characterHash];
if (character == null) {
// Something is wrong. Potentially, they didn't export the text as a glyph.
@ -269,14 +268,11 @@ class TextLayer extends BaseLayer {
switch (documentData.justification) {
case Justification.leftAlign:
canvas.translate(lineStart, lineOffset);
break;
case Justification.rightAlign:
canvas.translate(lineStart + boxWidth - lineWidth, lineOffset);
break;
case Justification.center:
canvas.translate(
lineStart + boxWidth / 2.0 - lineWidth / 2.0, lineOffset);
break;
}
}
@ -451,11 +447,8 @@ class TextLayer extends BaseLayer {
return;
}
if (paint.style == PaintingStyle.fill) {
textStyle = textStyle.copyWith(foreground: paint);
} else if (paint.style == PaintingStyle.stroke) {
textStyle = textStyle.copyWith(background: paint);
}
textStyle = textStyle.copyWith(foreground: paint);
var painter = TextPainter(
text: TextSpan(text: character, style: textStyle),
textDirection: _textDirection,

View File

@ -6,6 +6,16 @@ class LottieOptions {
/// instead of using merge paths.
final bool enableMergePaths;
LottieOptions({bool? enableMergePaths})
: enableMergePaths = enableMergePaths ?? false;
/// Enable layer-level opacity.
///
/// Add the ability to render opacity on the layer level rather than the shape level.
/// Opacity is normally applied directly to a shape. In cases where translucent shapes overlap,
/// applying opacity to a layer will be more accurate at the expense of performance.
/// Details: https://github.com/airbnb/lottie-android/issues/902
final bool enableApplyingOpacityToLayers;
LottieOptions({
this.enableMergePaths = false,
this.enableApplyingOpacityToLayers = false,
});
}

View File

@ -47,7 +47,6 @@ class AnimatablePathValueParser {
switch (reader.selectName(_names)) {
case 0:
pathAnimation = AnimatablePathValueParser.parse(reader, composition);
break;
case 1:
if (reader.peek() == Token.string) {
hasExpressions = true;
@ -55,7 +54,6 @@ class AnimatablePathValueParser {
} else {
xAnimation = AnimatableValueParser.parseFloat(reader, composition);
}
break;
case 2:
if (reader.peek() == Token.string) {
hasExpressions = true;
@ -63,7 +61,6 @@ class AnimatablePathValueParser {
} else {
yAnimation = AnimatableValueParser.parseFloat(reader, composition);
}
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -21,7 +21,6 @@ class AnimatableTextPropertiesParser {
switch (reader.selectName(_propertiesNames)) {
case 0:
anim = _parseAnimatableTextProperties(reader, composition);
break;
default:
reader.skipName();
reader.skipValue();
@ -47,16 +46,12 @@ class AnimatableTextPropertiesParser {
switch (reader.selectName(_animatablePropertiesNames)) {
case 0:
color = AnimatableValueParser.parseColor(reader, composition);
break;
case 1:
stroke = AnimatableValueParser.parseColor(reader, composition);
break;
case 2:
strokeWidth = AnimatableValueParser.parseFloat(reader, composition);
break;
case 3:
tracking = AnimatableValueParser.parseFloat(reader, composition);
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -45,21 +45,17 @@ class AnimatableTransformParser {
case 0:
anchorPoint =
AnimatablePathValueParser.parse(reader, composition);
break;
default:
reader.skipName();
reader.skipValue();
}
}
reader.endObject();
break;
case 1:
position =
AnimatablePathValueParser.parseSplitPath(reader, composition);
break;
case 2:
scale = AnimatableValueParser.parseScale(reader, composition);
break;
case 3:
case 4:
if (name == 3) {
@ -79,33 +75,25 @@ class AnimatableTransformParser {
rotation.keyframes.add(Keyframe(composition,
startValue: 0.0,
endValue: 0.0,
interpolator: null,
startFrame: 0.0,
endFrame: composition.endFrame));
} else if (rotation.keyframes.first.startValue == null) {
rotation.keyframes.first = Keyframe(composition,
startValue: 0.0,
endValue: 0.0,
interpolator: null,
startFrame: 0.0,
endFrame: composition.endFrame);
}
break;
case 5:
opacity = AnimatableValueParser.parseInteger(reader, composition);
break;
case 6:
startOpacity = AnimatableValueParser.parseFloat(reader, composition);
break;
case 7:
endOpacity = AnimatableValueParser.parseFloat(reader, composition);
break;
case 8:
skew = AnimatableValueParser.parseFloat(reader, composition);
break;
case 9:
skewAngle = AnimatableValueParser.parseFloat(reader, composition);
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -22,7 +22,6 @@ class BlurEffectParser {
}
}
reader.endArray();
break;
default:
reader.skipName();
reader.skipValue();
@ -40,7 +39,6 @@ class BlurEffectParser {
switch (reader.selectName(_innerBlurEffectNames)) {
case 0:
isCorrectType = reader.nextInt() == 0;
break;
case 1:
if (isCorrectType) {
blurEffect = BlurEffect(
@ -48,7 +46,6 @@ class BlurEffectParser {
} else {
reader.skipValue();
}
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -25,21 +25,16 @@ class CircleShapeParser {
switch (reader.selectName(_names)) {
case 0:
name = reader.nextString();
break;
case 1:
position =
AnimatablePathValueParser.parseSplitPath(reader, composition);
break;
case 2:
size = AnimatableValueParser.parsePoint(reader, composition);
break;
case 3:
hidden = reader.nextBoolean();
break;
case 4:
// "d" is 2 for normal and 3 for reversed.
reversed = reader.nextInt() == 3;
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -37,7 +37,6 @@ class ContentModelParser {
break typeLoop;
case 1:
d = reader.nextInt();
break;
default:
reader.skipName();
reader.skipValue();
@ -52,46 +51,32 @@ class ContentModelParser {
switch (type) {
case 'gr':
model = ShapeGroupParser.parse(reader, composition);
break;
case 'st':
model = ShapeStrokeParser.parse(reader, composition);
break;
case 'gs':
model = GradientStrokeParser.parse(reader, composition);
break;
case 'fl':
model = ShapeFillParser.parse(reader, composition);
break;
case 'gf':
model = GradientFillParser.parse(reader, composition);
break;
case 'tr':
model = AnimatableTransformParser.parse(reader, composition);
break;
case 'sh':
model = ShapePathParser.parse(reader, composition);
break;
case 'el':
model = CircleShapeParser.parse(reader, composition, d);
break;
case 'rc':
model = RectangleShapeParser.parse(reader, composition);
break;
case 'tm':
model = ShapeTrimPathParser.parse(reader, composition);
break;
case 'sr':
model = PolystarShapeParser.parse(reader, composition, d: d);
break;
case 'mm':
model = MergePathsParser.parse(reader);
break;
case 'rp':
model = RepeaterParser.parse(reader, composition);
break;
case 'rd':
model = RoundedCornersParser.parse(reader, composition);
break;
default:
composition.addWarning('Unknown shape type $type');
}

View File

@ -39,13 +39,10 @@ DocumentData documentDataParser(JsonReader reader) {
switch (reader.selectName(_names)) {
case 0:
text = reader.nextString();
break;
case 1:
fontName = reader.nextString();
break;
case 2:
size = reader.nextDouble();
break;
case 3:
var justificationInt = reader.nextInt();
if (justificationInt > Justification.center.index ||
@ -54,38 +51,28 @@ DocumentData documentDataParser(JsonReader reader) {
} else {
justification = Justification.values[justificationInt];
}
break;
case 4:
tracking = reader.nextInt();
break;
case 5:
lineHeight = reader.nextDouble();
break;
case 6:
baselineShift = reader.nextDouble();
break;
case 7:
fillColor = JsonUtils.jsonToColor(reader);
break;
case 8:
strokeColor = JsonUtils.jsonToColor(reader);
break;
case 9:
strokeWidth = reader.nextDouble();
break;
case 10:
strokeOverFill = reader.nextBoolean();
break;
case 11:
reader.beginArray();
boxPosition = Offset(reader.nextDouble(), reader.nextDouble());
reader.endArray();
break;
case 12:
reader.beginArray();
boxSize = Offset(reader.nextDouble(), reader.nextDouble());
reader.endArray();
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -27,7 +27,6 @@ class DropShadowEffectParser {
_maybeParseInnerEffect(reader, composition);
}
reader.endArray();
break;
default:
reader.skipName();
reader.skipValue();
@ -62,30 +61,23 @@ class DropShadowEffectParser {
switch (reader.selectName(_innerEffectNames)) {
case 0:
currentEffectName = reader.nextString();
break;
case 1:
switch (currentEffectName) {
case 'Shadow Color':
_color = AnimatableValueParser.parseColor(reader, composition);
break;
case 'Opacity':
_opacity = AnimatableValueParser.parseFloat(reader, composition);
break;
case 'Direction':
_direction =
AnimatableValueParser.parseFloat(reader, composition);
break;
case 'Distance':
_distance = AnimatableValueParser.parseFloat(reader, composition);
break;
case 'Softness':
_radius = AnimatableValueParser.parseFloat(reader, composition);
break;
default:
reader.skipValue();
break;
}
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -24,19 +24,14 @@ class FontCharacterParser {
switch (reader.selectName(_names)) {
case 0:
character = reader.nextString();
break;
case 1:
size = reader.nextDouble();
break;
case 2:
width = reader.nextDouble();
break;
case 3:
style = reader.nextString();
break;
case 4:
fontFamily = reader.nextString();
break;
case 5:
reader.beginObject();
while (reader.hasNext()) {
@ -44,18 +39,18 @@ class FontCharacterParser {
case 0:
reader.beginArray();
while (reader.hasNext()) {
shapes.add(ContentModelParser.parse(reader, composition)!
as ShapeGroup);
if (ContentModelParser.parse(reader, composition)
case var shape?) {
shapes.add(shape as ShapeGroup);
}
}
reader.endArray();
break;
default:
reader.skipName();
reader.skipValue();
}
}
reader.endObject();
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -18,16 +18,12 @@ class FontParser {
switch (reader.selectName(_names)) {
case 0:
family = reader.nextString();
break;
case 1:
name = reader.nextString();
break;
case 2:
style = reader.nextString();
break;
case 3:
ascent = reader.nextDouble();
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -69,17 +69,13 @@ class GradientColorParser {
case 0:
// position
positions[colorIndex] = value;
break;
case 1:
r = (value * 255).round();
break;
case 2:
g = (value * 255).round();
break;
case 3:
var b = (value * 255).round();
colors[colorIndex] = Color.fromARGB(255, r, g, b);
break;
}
}
@ -165,6 +161,9 @@ class GradientColorParser {
if (colorStopPosition < position && i != colorStopPositions.length - 1) {
continue;
}
if (i == colorStopPositions.length - 1 && position >= colorStopPosition) {
return colorStopColors[i].withOpacity(opacity);
}
// We found the position in which position is between i - 1 and i.
var distanceBetweenColors =
colorStopPositions[i] - colorStopPositions[i - 1];

View File

@ -31,7 +31,6 @@ class GradientFillParser {
switch (reader.selectName(_names)) {
case 0:
name = reader.nextString();
break;
case 1:
var points = -1;
reader.beginObject();
@ -39,39 +38,30 @@ class GradientFillParser {
switch (reader.selectName(_gradientNames)) {
case 0:
points = reader.nextInt();
break;
case 1:
color = AnimatableValueParser.parseGradientColor(
reader, composition, points);
break;
default:
reader.skipName();
reader.skipValue();
}
}
reader.endObject();
break;
case 2:
opacity = AnimatableValueParser.parseInteger(reader, composition);
break;
case 3:
gradientType =
reader.nextInt() == 1 ? GradientType.linear : GradientType.radial;
break;
case 4:
startPoint = AnimatableValueParser.parsePoint(reader, composition);
break;
case 5:
endPoint = AnimatableValueParser.parsePoint(reader, composition);
break;
case 6:
fillType = reader.nextInt() == 1
? PathFillType.nonZero
: PathFillType.evenOdd;
break;
case 7:
hidden = reader.nextBoolean();
break;
default:
reader.skipName();
reader.skipValue();
@ -90,8 +80,6 @@ class GradientFillParser {
opacity: opacity,
startPoint: startPoint!,
endPoint: endPoint!,
highlightLength: null,
highlightAngle: null,
hidden: hidden,
);
}

View File

@ -40,7 +40,6 @@ class GradientStrokeParser {
switch (reader.selectName(_names)) {
case 0:
name = reader.nextString();
break;
case 1:
var points = -1;
reader.beginObject();
@ -48,46 +47,34 @@ class GradientStrokeParser {
switch (reader.selectName(_gradientNames)) {
case 0:
points = reader.nextInt();
break;
case 1:
color = AnimatableValueParser.parseGradientColor(
reader, composition, points);
break;
default:
reader.skipName();
reader.skipValue();
}
}
reader.endObject();
break;
case 2:
opacity = AnimatableValueParser.parseInteger(reader, composition);
break;
case 3:
gradientType =
reader.nextInt() == 1 ? GradientType.linear : GradientType.radial;
break;
case 4:
startPoint = AnimatableValueParser.parsePoint(reader, composition);
break;
case 5:
endPoint = AnimatableValueParser.parsePoint(reader, composition);
break;
case 6:
width = AnimatableValueParser.parseFloat(reader, composition);
break;
case 7:
capType = LineCapType.values[reader.nextInt() - 1];
break;
case 8:
joinType = LineJoinType.values[reader.nextInt() - 1];
break;
case 9:
miterLimit = reader.nextDouble();
break;
case 10:
hidden = reader.nextBoolean();
break;
case 11:
reader.beginArray();
while (reader.hasNext()) {
@ -98,10 +85,8 @@ class GradientStrokeParser {
switch (reader.selectName(_dashPatternNames)) {
case 0:
n = reader.nextString();
break;
case 1:
val = AnimatableValueParser.parseFloat(reader, composition);
break;
default:
reader.skipName();
reader.skipValue();
@ -121,7 +106,6 @@ class GradientStrokeParser {
// If there is only 1 value then it is assumed to be equal parts on and off.
lineDashPattern.add(lineDashPattern[0]);
}
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -35,8 +35,14 @@ class JsonUtils {
return _jsonArrayToPoint(reader);
case Token.beginObject:
return _jsonObjectToPoint(reader);
// ignore: no_default_cases
default:
case Token.nullToken:
return Offset.zero;
case Token.endArray:
case Token.endObject:
case Token.name:
case Token.string:
case Token.boolean:
case Token.endDocument:
throw Exception('Unknown point starts with ${reader.peek()}');
}
}
@ -73,10 +79,8 @@ class JsonUtils {
switch (reader.selectName(_pointNames)) {
case 0:
x = valueFromObject(reader);
break;
case 1:
y = valueFromObject(reader);
break;
default:
reader.skipName();
reader.skipValue();
@ -99,8 +103,14 @@ class JsonUtils {
}
reader.endArray();
return val;
// ignore: no_default_cases
default:
case Token.endArray:
case Token.beginObject:
case Token.endObject:
case Token.name:
case Token.string:
case Token.boolean:
case Token.nullToken:
case Token.endDocument:
throw Exception('Unknown value for token of type $token');
}
}

View File

@ -58,28 +58,20 @@ class KeyframeParser {
switch (reader.selectName(_names)) {
case 0:
startFrame = reader.nextDouble();
break;
case 1:
startValue = valueParser(reader);
break;
case 2:
endValue = valueParser(reader);
break;
case 3:
cp1 = JsonUtils.jsonToPoint(reader);
break;
case 4:
cp2 = JsonUtils.jsonToPoint(reader);
break;
case 5:
hold = reader.nextInt() == 1;
break;
case 6:
pathCp1 = JsonUtils.jsonToPoint(reader);
break;
case 7:
pathCp2 = JsonUtils.jsonToPoint(reader);
break;
default:
reader.skipValue();
}
@ -96,12 +88,13 @@ class KeyframeParser {
interpolator = _linearInterpolator;
}
var keyframe = Keyframe<T>(composition,
startValue: startValue,
endValue: endValue,
interpolator: interpolator,
startFrame: startFrame,
endFrame: null);
var keyframe = Keyframe<T>(
composition,
startValue: startValue,
endValue: endValue,
interpolator: interpolator,
startFrame: startFrame,
);
keyframe.pathCp1 = pathCp1;
keyframe.pathCp2 = pathCp2;
return keyframe;
@ -136,13 +129,10 @@ class KeyframeParser {
switch (reader.selectName(_names)) {
case 0: // t
startFrame = reader.nextDouble();
break;
case 1: // s
startValue = valueParser(reader);
break;
case 2: // e
endValue = valueParser(reader);
break;
case 3: // o
if (reader.peek() == Token.beginObject) {
reader.beginObject();
@ -166,7 +156,6 @@ class KeyframeParser {
}
reader.endArray();
}
break;
case 1: // y
if (reader.peek() == Token.number) {
xCp1y = reader.nextDouble();
@ -181,7 +170,6 @@ class KeyframeParser {
}
reader.endArray();
}
break;
default:
reader.skipValue();
}
@ -192,7 +180,6 @@ class KeyframeParser {
} else {
cp1 = JsonUtils.jsonToPoint(reader);
}
break;
case 4: // i
if (reader.peek() == Token.beginObject) {
reader.beginObject();
@ -216,7 +203,6 @@ class KeyframeParser {
}
reader.endArray();
}
break;
case 1: // y
if (reader.peek() == Token.number) {
xCp2y = reader.nextDouble();
@ -231,7 +217,6 @@ class KeyframeParser {
}
reader.endArray();
}
break;
default:
reader.skipValue();
}
@ -242,16 +227,12 @@ class KeyframeParser {
} else {
cp2 = JsonUtils.jsonToPoint(reader);
}
break;
case 5: // h
hold = reader.nextInt() == 1;
break;
case 6: // to
pathCp1 = JsonUtils.jsonToPoint(reader);
break;
case 7: // ti
pathCp2 = JsonUtils.jsonToPoint(reader);
break;
default:
reader.skipValue();
}

View File

@ -44,7 +44,6 @@ class KeyframesParser {
keyframes.add(KeyframeParser.parse(reader, composition, valueParser,
animated: false, multiDimensional: multiDimensional));
}
break;
default:
reader.skipValue();
}

View File

@ -58,7 +58,6 @@ class LayerParser {
id: -1,
layerType: LayerType.preComp,
parentId: -1,
refId: null,
masks: <Mask>[],
transform: AnimatableTransform(),
solidWidth: 0,
@ -68,11 +67,8 @@ class LayerParser {
startFrame: 0,
preCompWidth: bounds.width,
preCompHeight: bounds.height,
text: null,
textProperties: null,
inOutKeyframes: <Keyframe<double>>[],
matteType: MatteType.none,
timeRemapping: null,
isHidden: false);
}
@ -117,13 +113,10 @@ class LayerParser {
switch (reader.selectName(_names)) {
case 0:
layerName = reader.nextString();
break;
case 1:
layerId = reader.nextInt();
break;
case 2:
refId = reader.nextString();
break;
case 3:
var layerTypeInt = reader.nextInt();
if (layerTypeInt < LayerType.unknown.index) {
@ -131,23 +124,17 @@ class LayerParser {
} else {
layerType = LayerType.unknown;
}
break;
case 4:
parentId = reader.nextInt();
break;
case 5:
solidWidth = reader.nextInt();
break;
case 6:
solidHeight = reader.nextInt();
break;
case 7:
solidColor = MiscUtils.parseColor(reader.nextString(),
warningCallback: composition.addWarning);
break;
case 8:
transform = AnimatableTransformParser.parse(reader, composition);
break;
case 9:
var matteTypeIndex = reader.nextInt();
if (matteTypeIndex >= MatteType.values.length) {
@ -161,7 +148,6 @@ class LayerParser {
composition.addWarning('Unsupported matte type: Luma Inverted');
}
composition.incrementMatteOrMaskCount(1);
break;
case 10:
reader.beginArray();
while (reader.hasNext()) {
@ -169,7 +155,6 @@ class LayerParser {
}
composition.incrementMatteOrMaskCount(masks.length);
reader.endArray();
break;
case 11:
reader.beginArray();
while (reader.hasNext()) {
@ -179,7 +164,6 @@ class LayerParser {
}
}
reader.endArray();
break;
case 12:
reader.beginObject();
while (reader.hasNext()) {
@ -187,7 +171,6 @@ class LayerParser {
case 0:
text = AnimatableValueParser.parseDocumentData(
reader, composition);
break;
case 1:
reader.beginArray();
if (reader.hasNext()) {
@ -198,14 +181,12 @@ class LayerParser {
reader.skipValue();
}
reader.endArray();
break;
default:
reader.skipName();
reader.skipValue();
}
}
reader.endObject();
break;
case 13:
reader.beginArray();
var effectNames = <String>[];
@ -221,11 +202,9 @@ class LayerParser {
dropShadowEffect =
DropShadowEffectParser().parse(reader, composition);
}
break;
case 1:
var effectName = reader.nextString();
effectNames.add(effectName);
break;
default:
reader.skipName();
reader.skipValue();
@ -238,34 +217,24 @@ class LayerParser {
"Lottie doesn't support layer effects. If you are using them for "
' fills, strokes, trim paths etc. then try adding them directly as contents '
' in your shape. Found: $effectNames');
break;
case 14:
timeStretch = reader.nextDouble();
break;
case 15:
startFrame = reader.nextDouble();
break;
case 16:
preCompWidth = reader.nextInt();
break;
case 17:
preCompHeight = reader.nextInt();
break;
case 18:
inFrame = reader.nextDouble();
break;
case 19:
outFrame = reader.nextDouble();
break;
case 20:
timeRemapping = AnimatableValueParser.parseFloat(reader, composition);
break;
case 21:
cl = reader.nextString();
break;
case 22:
hidden = reader.nextBoolean();
break;
default:
reader.skipName();
reader.skipValue();
@ -277,11 +246,7 @@ class LayerParser {
// Before the in frame
if (inFrame > 0) {
var preKeyframe = Keyframe<double>(composition,
startValue: 0.0,
endValue: 0.0,
interpolator: null,
startFrame: 0.0,
endFrame: inFrame);
startValue: 0.0, endValue: 0.0, startFrame: 0.0, endFrame: inFrame);
inOutKeyframes.add(preKeyframe);
}
@ -289,7 +254,6 @@ class LayerParser {
var visibleKeyframe = Keyframe<double>(composition,
startValue: 1.0,
endValue: 1.0,
interpolator: null,
startFrame: inFrame,
endFrame: outFrame);
inOutKeyframes.add(visibleKeyframe);
@ -297,7 +261,6 @@ class LayerParser {
var outKeyframe = Keyframe<double>(composition,
startValue: 0.0,
endValue: 0.0,
interpolator: null,
startFrame: outFrame,
endFrame: double.maxFinite);
inOutKeyframes.add(outKeyframe);

View File

@ -33,20 +33,15 @@ class LottieCompositionParser {
while (reader.hasNext()) {
switch (reader.selectName(_names)) {
case 0:
parameters.bounds.width = (reader.nextInt()).round();
break;
parameters.bounds.width = reader.nextInt();
case 1:
parameters.bounds.height = (reader.nextInt()).round();
break;
parameters.bounds.height = reader.nextInt();
case 2:
parameters.startFrame = reader.nextDouble();
break;
case 3:
parameters.endFrame = reader.nextDouble() - 0.01;
break;
case 4:
parameters.frameRate = reader.nextDouble();
break;
case 5:
var version = reader.nextString();
var versions = version.split('.');
@ -57,24 +52,18 @@ class LottieCompositionParser {
majorVersion, minorVersion, patchVersion, 4, 4, 0)) {
composition.addWarning('Lottie only supports bodymovin >= 4.4.0');
}
break;
case 6:
_parseLayers(
reader, composition, parameters.layers, parameters.layerMap);
break;
case 7:
_parseAssets(
reader, composition, parameters.precomps, parameters.images);
break;
case 8:
_parseFonts(reader, parameters.fonts);
break;
case 9:
_parseChars(reader, composition, parameters.characters);
break;
case 10:
_parseMarkers(reader, composition, parameters.markers);
break;
default:
reader.skipName();
reader.skipValue();
@ -136,7 +125,6 @@ class LottieCompositionParser {
switch (reader.selectName(_assetsNames)) {
case 0:
id = reader.nextString();
break;
case 1:
reader.beginArray();
while (reader.hasNext()) {
@ -145,19 +133,14 @@ class LottieCompositionParser {
layers.add(layer);
}
reader.endArray();
break;
case 2:
width = reader.nextInt();
break;
case 3:
height = reader.nextInt();
break;
case 4:
imageFileName = reader.nextString();
break;
case 5:
relativeFolder = reader.nextString();
break;
default:
reader.skipName();
reader.skipValue();
@ -192,7 +175,6 @@ class LottieCompositionParser {
fonts[font.name] = font;
}
reader.endArray();
break;
default:
reader.skipName();
reader.skipValue();
@ -226,13 +208,10 @@ class LottieCompositionParser {
switch (reader.selectName(_markerNames)) {
case 0:
comment = reader.nextString();
break;
case 1:
frame = reader.nextDouble();
break;
case 2:
durationFrames = reader.nextDouble();
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -23,33 +23,25 @@ class MaskParser {
switch (modeName) {
case 'a':
maskMode = MaskMode.maskModeAdd;
break;
case 's':
maskMode = MaskMode.maskModeSubstract;
break;
case 'n':
maskMode = MaskMode.maskModeNone;
break;
case 'i':
composition.addWarning(
'Animation contains intersect masks. They are not supported but will be treated like add masks.');
maskMode = MaskMode.maskModeIntersect;
break;
default:
composition.addWarning(
'Unknown mask mode $modeName. Defaulting to Add.');
maskMode = MaskMode.maskModeAdd;
}
break;
case 'pt':
maskPath = AnimatableValueParser.parseShapeData(reader, composition);
break;
case 'o':
opacity = AnimatableValueParser.parseInteger(reader, composition);
break;
case 'inv':
inverted = reader.nextBoolean();
break;
default:
reader.skipValue();
}

View File

@ -16,13 +16,10 @@ class MergePathsParser {
switch (reader.selectName(_names)) {
case 0:
name = reader.nextString();
break;
case 1:
mode = MergePaths.modeForId(reader.nextInt());
break;
case 2:
hidden = reader.nextBoolean();
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -1,11 +1,10 @@
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
class Buffer {
Buffer(this.buffer);
final Uint8List buffer;
final List<int> buffer;
int _start = 0, _size = 0;
int get size => _size;

View File

@ -1,5 +1,4 @@
import 'dart:convert';
import 'dart:typed_data';
import 'buffer.dart';
import 'json_scope.dart';
import 'json_utf8_reader.dart';
@ -167,7 +166,7 @@ abstract class JsonReader {
bool failOnUnknown = false;
/// Returns a new instance that reads UTF-8 encoded JSON from {@code source}.
static JsonReader fromBytes(Uint8List source) {
static JsonReader fromBytes(List<int> source) {
return JsonUtf8Reader(Buffer(source));
}

View File

@ -43,7 +43,6 @@ class JsonScope {
..write('[')
..write(pathIndices[i])
..write(']');
break;
case emptyObject:
case danglingName:
@ -52,7 +51,6 @@ class JsonScope {
if (pathNames[i] != null) {
result.write(pathNames[i]);
}
break;
case nonEmptyDocument:
case emptyDocument:

View File

@ -200,7 +200,6 @@ class JsonUtf8Reader extends JsonReader {
return _peeked = peekedEndArray;
case $semicolon:
_checkLenient();
break;
case $comma:
break;
default:
@ -218,7 +217,6 @@ class JsonUtf8Reader extends JsonReader {
return _peeked = peekedEndObject;
case $semicolon:
_checkLenient(); // fall-through
break;
case $comma:
break;
default:
@ -262,7 +260,6 @@ class JsonUtf8Reader extends JsonReader {
if (buffer.request(1) && buffer.getByte(0) == $greaterThan) {
buffer.readByte(); // Consume '>'.
}
break;
default:
throw syntaxError("Expected ':'");
}

View File

@ -31,41 +31,30 @@ class PolystarShapeParser {
switch (reader.selectName(_names)) {
case 0:
name = reader.nextString();
break;
case 1:
type = PolystarShapeType.forValue(reader.nextInt());
break;
case 2:
points = AnimatableValueParser.parseFloat(reader, composition);
break;
case 3:
position =
AnimatablePathValueParser.parseSplitPath(reader, composition);
break;
case 4:
rotation = AnimatableValueParser.parseFloat(reader, composition);
break;
case 5:
outerRadius = AnimatableValueParser.parseFloat(reader, composition);
break;
case 6:
outerRoundedness =
AnimatableValueParser.parseFloat(reader, composition);
break;
case 7:
innerRadius = AnimatableValueParser.parseFloat(reader, composition);
break;
case 8:
innerRoundedness =
AnimatableValueParser.parseFloat(reader, composition);
break;
case 9:
hidden = reader.nextBoolean();
break;
case 10:
// "d" is 2 for normal and 3 for reversed.
reversed = reader.nextInt() == 3;
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -25,20 +25,15 @@ class RectangleShapeParser {
switch (reader.selectName(_names)) {
case 0:
name = reader.nextString();
break;
case 1:
position =
AnimatablePathValueParser.parseSplitPath(reader, composition);
break;
case 2:
size = AnimatableValueParser.parsePoint(reader, composition);
break;
case 3:
roundedness = AnimatableValueParser.parseFloat(reader, composition);
break;
case 4:
hidden = reader.nextBoolean();
break;
default:
reader.skipValue();
}

View File

@ -23,19 +23,14 @@ class RepeaterParser {
switch (reader.selectName(_names)) {
case 0:
name = reader.nextString();
break;
case 1:
copies = AnimatableValueParser.parseFloat(reader, composition);
break;
case 2:
offset = AnimatableValueParser.parseFloat(reader, composition);
break;
case 3:
transform = AnimatableTransformParser.parse(reader, composition);
break;
case 4:
hidden = reader.nextBoolean();
break;
default:
reader.skipValue();
}

View File

@ -21,18 +21,15 @@ class RoundedCornersParser {
switch (reader.selectName(_names)) {
case 0: //nm
name = reader.nextString();
break;
case 1: // r
cornerRadius = AnimatableValueParser.parseFloat(reader, composition);
break;
case 2: // hd
hidden = reader.nextBoolean();
break;
default:
reader.skipValue();
}
}
return hidden ? null : RoundedCorners(name!, cornerRadius!);
return hidden ? null : RoundedCorners(name ?? '', cornerRadius!);
}
}

View File

@ -23,16 +23,12 @@ ShapeData shapeDataParser(JsonReader reader) {
switch (reader.selectName(_names)) {
case 0:
closed = reader.nextBoolean();
break;
case 1:
pointsArray = JsonUtils.jsonToPoints(reader);
break;
case 2:
inTangents = JsonUtils.jsonToPoints(reader);
break;
case 3:
outTangents = JsonUtils.jsonToPoints(reader);
break;
default:
reader.skipName();
reader.skipValue();
@ -51,7 +47,7 @@ ShapeData shapeDataParser(JsonReader reader) {
if (pointsArray.isEmpty) {
return ShapeData(<CubicCurveData>[],
initialPoint: const Offset(0, 0), closed: false);
initialPoint: Offset.zero, closed: false);
}
var length = pointsArray.length;

View File

@ -25,22 +25,16 @@ class ShapeFillParser {
switch (reader.selectName(_names)) {
case 0:
name = reader.nextString();
break;
case 1:
color = AnimatableValueParser.parseColor(reader, composition);
break;
case 2:
opacity = AnimatableValueParser.parseInteger(reader, composition);
break;
case 3:
fillEnabled = reader.nextBoolean();
break;
case 4:
fillTypeInt = reader.nextInt();
break;
case 5:
hidden = reader.nextBoolean();
break;
default:
reader.skipName();
reader.skipValue();

View File

@ -18,10 +18,8 @@ class ShapeGroupParser {
switch (reader.selectName(_names)) {
case 0:
name = reader.nextString();
break;
case 1:
hidden = reader.nextBoolean();
break;
case 2:
reader.beginArray();
while (reader.hasNext()) {
@ -31,7 +29,6 @@ class ShapeGroupParser {
}
}
reader.endArray();
break;
default:
reader.skipValue();
}

View File

@ -20,16 +20,12 @@ class ShapePathParser {
switch (reader.selectName(_names)) {
case 0:
name = reader.nextString();
break;
case 1:
ind = reader.nextInt();
break;
case 2:
shape = AnimatableValueParser.parseShapeData(reader, composition);
break;
case 3:
hidden = reader.nextBoolean();
break;
default:
reader.skipValue();
}

View File

@ -32,28 +32,20 @@ class ShapeStrokeParser {
switch (reader.selectName(_names)) {
case 0:
name = reader.nextString();
break;
case 1:
color = AnimatableValueParser.parseColor(reader, composition);
break;
case 2:
width = AnimatableValueParser.parseFloat(reader, composition);
break;
case 3:
opacity = AnimatableValueParser.parseInteger(reader, composition);
break;
case 4:
capType = LineCapType.values[reader.nextInt() - 1];
break;
case 5:
joinType = LineJoinType.values[reader.nextInt() - 1];
break;
case 6:
miterLimit = reader.nextDouble();
break;
case 7:
hidden = reader.nextBoolean();
break;
case 8:
reader.beginArray();
while (reader.hasNext()) {
@ -65,10 +57,8 @@ class ShapeStrokeParser {
switch (reader.selectName(_dashPatternNames)) {
case 0:
n = reader.nextString();
break;
case 1:
val = AnimatableValueParser.parseFloat(reader, composition);
break;
default:
reader.skipName();
reader.skipValue();
@ -79,12 +69,10 @@ class ShapeStrokeParser {
switch (n) {
case 'o':
offset = val;
break;
case 'd':
case 'g':
composition.hasDashPattern = true;
lineDashPattern.add(val!);
break;
}
}
reader.endArray();
@ -93,7 +81,6 @@ class ShapeStrokeParser {
// If there is only 1 value then it is assumed to be equal parts on and off.
lineDashPattern.add(lineDashPattern.first);
}
break;
default:
reader.skipValue();
}

View File

@ -20,22 +20,16 @@ class ShapeTrimPathParser {
switch (reader.selectName(_names)) {
case 0:
start = AnimatableValueParser.parseFloat(reader, composition);
break;
case 1:
end = AnimatableValueParser.parseFloat(reader, composition);
break;
case 2:
offset = AnimatableValueParser.parseFloat(reader, composition);
break;
case 3:
name = reader.nextString();
break;
case 4:
type = ShapeTrimPath.typeForId(reader.nextInt());
break;
case 5:
hidden = reader.nextBoolean();
break;
default:
reader.skipValue();
}

View File

@ -8,6 +8,7 @@ import '../lottie_image_asset.dart';
import 'load_image.dart';
import 'lottie_provider.dart';
@immutable
class AssetLottie extends LottieProvider {
AssetLottie(
this.assetName, {

View File

@ -1,4 +1,5 @@
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:path/path.dart' as p;
import '../composition.dart';
import '../lottie_image_asset.dart';
@ -6,6 +7,7 @@ import 'load_image.dart';
import 'lottie_provider.dart';
import 'provider_io.dart' if (dart.library.html) 'provider_web.dart' as io;
@immutable
class FileLottie extends LottieProvider {
FileLottie(this.file, {super.imageProviderFactory});

View File

@ -1,5 +1,5 @@
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:path/path.dart' as p;
import '../composition.dart';
@ -7,6 +7,7 @@ import '../lottie_image_asset.dart';
import 'load_image.dart';
import 'lottie_provider.dart';
@immutable
class MemoryLottie extends LottieProvider {
MemoryLottie(this.bytes, {super.imageProviderFactory});

View File

@ -8,6 +8,7 @@ import 'load_image.dart';
import 'lottie_provider.dart';
import 'provider_io.dart' if (dart.library.html) 'provider_web.dart' as network;
@immutable
class NetworkLottie extends LottieProvider {
NetworkLottie(this.url, {this.headers, super.imageProviderFactory});

View File

@ -86,6 +86,7 @@ class RawLottie extends LeafRenderObjectWidget {
composition: composition,
delegates: delegates,
enableMergePaths: options?.enableMergePaths,
enableApplyingOpacityToLayers: options?.enableApplyingOpacityToLayers,
progress: progress,
frameRate: frameRate,
width: width,
@ -105,6 +106,7 @@ class RawLottie extends LeafRenderObjectWidget {
frameRate: frameRate,
delegates: delegates,
enableMergePaths: options?.enableMergePaths,
enableApplyingOpacityToLayers: options?.enableApplyingOpacityToLayers,
filterQuality: filterQuality,
)
..width = width

View File

@ -13,6 +13,7 @@ class RenderLottie extends RenderBox {
required LottieComposition? composition,
LottieDelegates? delegates,
bool? enableMergePaths,
bool? enableApplyingOpacityToLayers,
double progress = 0.0,
FrameRate? frameRate,
double? width,
@ -26,6 +27,8 @@ class RenderLottie extends RenderBox {
..setProgress(progress, frameRate: frameRate)
..delegates = delegates
..enableMergePaths = enableMergePaths ?? false
..isApplyingOpacityToLayersEnabled =
enableApplyingOpacityToLayers ?? false
..filterQuality = filterQuality)
: null,
_width = width,
@ -42,9 +45,11 @@ class RenderLottie extends RenderBox {
required FrameRate? frameRate,
required LottieDelegates? delegates,
bool? enableMergePaths,
bool? enableApplyingOpacityToLayers,
FilterQuality? filterQuality}) {
var drawable = _drawable;
enableMergePaths ??= false;
enableApplyingOpacityToLayers ??= false;
var needsLayout = false;
var needsPaint = false;
@ -71,6 +76,12 @@ class RenderLottie extends RenderBox {
drawable.enableMergePaths = enableMergePaths;
needsPaint = true;
}
if (enableApplyingOpacityToLayers !=
drawable.isApplyingOpacityToLayersEnabled) {
drawable.isApplyingOpacityToLayersEnabled =
enableApplyingOpacityToLayers;
needsPaint = true;
}
if (filterQuality != drawable.filterQuality) {
drawable.filterQuality = filterQuality;
needsPaint = true;
@ -91,6 +102,7 @@ class RenderLottie extends RenderBox {
/// aspect ratio.
double? get width => _width;
double? _width;
set width(double? value) {
if (value == _width) {
return;
@ -105,6 +117,7 @@ class RenderLottie extends RenderBox {
/// aspect ratio.
double? get height => _height;
double? _height;
set height(double? value) {
if (value == _height) {
return;
@ -116,6 +129,7 @@ class RenderLottie extends RenderBox {
/// How to inscribe the composition into the space allocated during layout.
BoxFit? get fit => _fit;
BoxFit? _fit;
set fit(BoxFit? value) {
if (value == _fit) {
return;
@ -130,6 +144,7 @@ class RenderLottie extends RenderBox {
/// not be null.
AlignmentGeometry get alignment => _alignment;
AlignmentGeometry _alignment;
set alignment(AlignmentGeometry value) {
if (value == _alignment) {
return;

View File

@ -1,189 +0,0 @@
import 'dart:ui';
import 'package:flutter/foundation.dart';
class DebugPath extends Path {
void _log(String methodName) {
debugPrint('Path.$methodName');
}
@override
void addArc(Rect oval, double startAngle, double sweepAngle) {
_log('addArc');
super.addArc(oval, startAngle, sweepAngle);
}
@override
void addOval(Rect oval) {
_log('addOval');
super.addOval(oval);
}
@override
void addPath(Path path, Offset offset, {Float64List? matrix4}) {
_log('addPath');
super.addPath(path, offset, matrix4: matrix4);
}
@override
void addPolygon(List<Offset> points, bool close) {
_log('addPolygon');
super.addPolygon(points, close);
}
@override
void addRRect(RRect rrect) {
_log('addRRect');
super.addRRect(rrect);
}
@override
void addRect(Rect rect) {
_log('addRect');
super.addRect(rect);
}
@override
void arcTo(
Rect rect, double startAngle, double sweepAngle, bool forceMoveTo) {
_log('arcTo');
super.arcTo(rect, startAngle, sweepAngle, forceMoveTo);
}
@override
void arcToPoint(Offset arcEnd,
{Radius radius = Radius.zero,
double rotation = 0.0,
bool largeArc = false,
bool clockwise = true}) {
_log('arcToPoint');
super.arcToPoint(arcEnd,
radius: radius,
rotation: rotation,
largeArc: largeArc,
clockwise: clockwise);
}
@override
void close() {
_log('close');
super.close();
}
@override
PathMetrics computeMetrics({bool forceClosed = false}) {
_log('computeMetrics');
return super.computeMetrics();
}
@override
void conicTo(double x1, double y1, double x2, double y2, double w) {
_log('conicTo');
super.conicTo(x1, y1, x2, y2, w);
}
@override
bool contains(Offset point) {
_log('contains');
return super.contains(point);
}
@override
void cubicTo(
double x1, double y1, double x2, double y2, double x3, double y3) {
_log('cubicTo');
super.cubicTo(x1, y1, x2, y2, x3, y3);
}
@override
void extendWithPath(Path path, Offset offset, {Float64List? matrix4}) {
_log('extendWithPath');
super.extendWithPath(path, offset, matrix4: matrix4);
}
@override
Rect getBounds() {
_log('getBounds');
return super.getBounds();
}
@override
void lineTo(double x, double y) {
_log('lineTo');
super.lineTo(x, y);
}
@override
void moveTo(double x, double y) {
_log('moveTo');
super.moveTo(x, y);
}
@override
void quadraticBezierTo(double x1, double y1, double x2, double y2) {
_log('quadraticBezierTo');
super.quadraticBezierTo(x1, y1, x2, y2);
}
@override
void relativeArcToPoint(Offset arcEndDelta,
{Radius radius = Radius.zero,
double rotation = 0.0,
bool largeArc = false,
bool clockwise = true}) {
_log('relativeArcToPoint');
super.relativeArcToPoint(arcEndDelta,
radius: radius,
rotation: rotation,
largeArc: largeArc,
clockwise: clockwise);
}
@override
void relativeConicTo(double x1, double y1, double x2, double y2, double w) {
_log('relativeConicTo');
super.relativeConicTo(x1, y1, x2, y2, w);
}
@override
void relativeCubicTo(
double x1, double y1, double x2, double y2, double x3, double y3) {
_log('relativeCubicTo');
super.relativeCubicTo(x1, y1, x2, y2, x3, y3);
}
@override
void relativeLineTo(double dx, double dy) {
_log('relativeLineTo');
super.relativeLineTo(dx, dy);
}
@override
void relativeMoveTo(double dx, double dy) {
_log('relativeMoveTo');
super.relativeMoveTo(dx, dy);
}
@override
void relativeQuadraticBezierTo(double x1, double y1, double x2, double y2) {
_log('relativeQuadraticBezierTo');
super.relativeQuadraticBezierTo(x1, y1, x2, y2);
}
@override
void reset() {
_log('reset');
super.reset();
}
@override
Path shift(Offset offset) {
_log('shift');
return super.shift(offset);
}
@override
Path transform(Float64List matrix4) {
_log('transform');
return super.transform(matrix4);
}
}

View File

@ -13,7 +13,7 @@ class GammaEvaluator {
// IEC 61966-2-1:1999
return linear <= 0.0031308
? linear * 12.92
: ((pow(linear, 1.0 / 2.4) * 1.055) - 0.055).toDouble();
: ((pow(linear, 1.0 / 2.4) * 1.055) - 0.055);
}
// Electro-optical conversion function for the sRGB color space

View File

@ -52,7 +52,7 @@ class MiscUtils {
}
static Color parseColor(String colorString,
{required Function(String) warningCallback}) {
{required void Function(String) warningCallback}) {
if (colorString.isNotEmpty && colorString[0] == '#') {
// Use a long to avoid rollovers on #ffXXXXXX
var color = int.parse(colorString.substring(1), radix: 16);
@ -71,12 +71,19 @@ class MiscUtils {
}
static int floorMod(double x, double y) {
return x.toInt() - y.toInt() * _floorDiv(x.toInt(), y.toInt());
var xInt = x.toInt();
var yInt = y.toInt();
return xInt - yInt * _floorDiv(xInt, yInt);
}
static int floorModInt(int x, int y) {
return x - y * _floorDiv(x, y);
}
static int _floorDiv(int x, int y) {
var r = x ~/ y;
var sameSign = (x ^ y) >= 0;
var sameSign = x.sign == y.sign;
var mod = x % y;
if (!sameSign && mod != 0) {
r--;

View File

@ -104,16 +104,13 @@ class Utils {
newStart -= length;
}
var tempPath =
pathMeasure.extractPath(newStart, newEnd, startWithMoveTo: true);
var tempPath = pathMeasure.extractPath(newStart, newEnd);
if (newEnd > length) {
var tempPath2 =
pathMeasure.extractPath(0, newEnd % length, startWithMoveTo: true);
var tempPath2 = pathMeasure.extractPath(0, newEnd % length);
tempPath.addPath(tempPath2, Offset.zero);
} else if (newStart < 0) {
var tempPath2 = pathMeasure.extractPath(length + newStart, length,
startWithMoveTo: true);
var tempPath2 = pathMeasure.extractPath(length + newStart, length);
tempPath.addPath(tempPath2, Offset.zero);
}
path.set(tempPath);

View File

@ -1,5 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart';
@immutable
class DropShadow {
final Color color;
final double direction;

View File

@ -5,42 +5,42 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: a36ec4843dc30ea6bf652bf25e3448db6c5e8bcf4aa55f063a5d1dad216d8214
sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051
url: "https://pub.dev"
source: hosted
version: "58.0.0"
version: "64.0.0"
analyzer:
dependency: "direct dev"
description:
name: analyzer
sha256: cc4242565347e98424ce9945c819c192ec0838cb9d1f6aa4a97cc96becbc5b27
sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893"
url: "https://pub.dev"
source: hosted
version: "5.10.0"
version: "6.2.0"
archive:
dependency: "direct main"
description:
name: archive
sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d
sha256: "7e0d52067d05f2e0324268097ba723b71cb41ac8a6a2b24d1edf9c536b987b03"
url: "https://pub.dev"
source: hosted
version: "3.3.6"
version: "3.4.6"
args:
dependency: transitive
description:
name: args
sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440"
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.2"
async:
dependency: transitive
description:
name: async
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.10.0"
version: "2.11.0"
boolean_selector:
dependency: transitive
description:
@ -53,10 +53,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "1.3.0"
clock:
dependency: transitive
description:
@ -69,10 +69,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
url: "https://pub.dev"
source: hosted
version: "1.17.0"
version: "1.17.2"
convert:
dependency: transitive
description:
@ -85,18 +85,18 @@ packages:
dependency: transitive
description:
name: crypto
sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.2"
version: "3.0.3"
dart_style:
dependency: "direct dev"
description:
name: dart_style
sha256: "6d691edde054969f0e0f26abb1b30834b5138b963793e56f69d3a9a4435e6352"
sha256: abd7625e16f51f554ea244d090292945ec4d4be7bfbaf2ec8cccea568919d334
url: "https://pub.dev"
source: hosted
version: "2.3.0"
version: "2.3.3"
fake_async:
dependency: transitive
description:
@ -109,10 +109,10 @@ packages:
dependency: transitive
description:
name: file
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "6.1.4"
version: "7.0.0"
flutter:
dependency: "direct main"
description: flutter
@ -122,10 +122,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_lints
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
sha256: ad76540d21c066228ee3f9d1dad64a9f7e46530e8bb7c85011a88bc1fd874bc5
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "3.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -135,50 +135,50 @@ packages:
dependency: transitive
description:
name: glob
sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
js:
dependency: transitive
description:
name: js
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
version: "0.6.5"
version: "0.6.7"
lints:
dependency: transitive
description:
name: lints
sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593"
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "3.0.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev"
source: hosted
version: "0.12.13"
version: "0.12.16"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
version: "0.5.0"
meta:
dependency: transitive
description:
name: meta
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
url: "https://pub.dev"
source: hosted
version: "1.8.0"
version: "1.9.1"
package_config:
dependency: transitive
description:
@ -191,26 +191,26 @@ packages:
dependency: "direct main"
description:
name: path
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev"
source: hosted
version: "1.8.2"
version: "1.8.3"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: c3120a968135aead39699267f4c74bc9a08e4e909e86bc1b0af5bfd78691123c
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
url: "https://pub.dev"
source: hosted
version: "3.7.2"
version: "3.7.3"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17"
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
url: "https://pub.dev"
source: hosted
version: "2.1.3"
version: "2.1.4"
sky_engine:
dependency: transitive
description: flutter
@ -220,10 +220,10 @@ packages:
dependency: transitive
description:
name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.10.0"
stack_trace:
dependency: transitive
description:
@ -260,18 +260,18 @@ packages:
dependency: transitive
description:
name: test_api
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
url: "https://pub.dev"
source: hosted
version: "0.4.16"
version: "0.6.0"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.1"
version: "1.3.2"
vector_math:
dependency: "direct main"
description:
@ -284,18 +284,26 @@ packages:
dependency: transitive
description:
name: watcher
sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
version: "1.1.0"
web:
dependency: transitive
description:
name: web
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
url: "https://pub.dev"
source: hosted
version: "0.1.4-beta"
yaml:
dependency: "direct dev"
description:
name: yaml
sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370"
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
version: "3.1.2"
sdks:
dart: ">=2.19.0 <3.0.0"
flutter: ">=3.3.0"
dart: ">=3.1.0 <4.0.0"
flutter: ">=3.13.0"

View File

@ -1,11 +1,11 @@
name: lottie
description: Render After Effects animations natively on Flutter. This package is a pure Dart implementation of a Lottie player.
version: 2.3.1
version: 2.7.0
repository: https://github.com/xvrh/lottie-flutter
environment:
sdk: '>=2.18.0 <3.0.0'
flutter: '>=3.3.0'
sdk: '^3.1.0'
flutter: '>=3.13.0'
dependencies:
archive: ^3.0.0

View File

@ -9,8 +9,8 @@ import 'utils.dart';
void main() {
testWidgets('Can specify ImageProvider with zip file ', (tester) async {
var size = const Size(500, 400);
tester.binding.window.physicalSizeTestValue = size;
tester.binding.window.devicePixelRatioTestValue = 1.0;
tester.view.physicalSize = size;
tester.view.devicePixelRatio = 1.0;
var callCount = 0;
ImageProvider imageProviderFactory(LottieImageAsset image) {
@ -32,8 +32,8 @@ void main() {
testWidgets('Can specify image delegate', (tester) async {
var size = const Size(500, 400);
tester.binding.window.physicalSizeTestValue = size;
tester.binding.window.devicePixelRatioTestValue = 1.0;
tester.view.physicalSize = size;
tester.view.devicePixelRatio = 1.0;
var image = await tester.runAsync(() async =>
loadImage(FileImage(File('example/assets/Images/WeAccept/img_0.png'))));

View File

@ -276,7 +276,7 @@ void main() {
testGolden(
'Null Color Filter',
ValueDelegate.colorFilter(['**'], value: null),
ValueDelegate.colorFilter(['**']),
);
testGolden(
@ -308,6 +308,15 @@ void main() {
),
);
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)',
@ -320,8 +329,8 @@ void main() {
testWidgets('warningShimmer', (tester) async {
var size = const Size(500, 400);
tester.binding.window.physicalSizeTestValue = size;
tester.binding.window.devicePixelRatioTestValue = 1.0;
tester.view.physicalSize = size;
tester.view.devicePixelRatio = 1.0;
var composition = await LottieComposition.fromBytes(
File('test/data/warningShimmer.json').readAsBytesSync());

View File

@ -10,8 +10,8 @@ void main() {
testWidgets('Mirror animation', (tester) async {
var size = const Size(500, 400);
tester.binding.window.physicalSizeTestValue = size;
tester.binding.window.devicePixelRatioTestValue = 1.0;
tester.view.physicalSize = size;
tester.view.devicePixelRatio = 1.0;
var composition = (await tester.runAsync(() =>
FileLottie(File('$root/Tests/MatteTimeStretchScan.json')).load()))!;

View File

@ -9,8 +9,8 @@ import 'utils.dart';
void main() {
testWidgets('Animations with stroke', (tester) async {
var size = const Size(500, 400);
tester.binding.window.physicalSizeTestValue = size;
tester.binding.window.devicePixelRatioTestValue = 1.0;
tester.view.physicalSize = size;
tester.view.devicePixelRatio = 1.0;
var composition = await LottieComposition.fromBytes(
File('example/assets/17297-fireworks.json').readAsBytesSync());

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 154 KiB

View File

@ -14,8 +14,8 @@ void main() {
.where((f) => const ['.json', '.zip'].contains(p.extension(f.path)))) {
testWidgets('Goldens ${asset.path}', (tester) async {
var size = const Size(500, 400);
tester.binding.window.physicalSizeTestValue = size;
tester.binding.window.devicePixelRatioTestValue = 1.0;
tester.view.physicalSize = size;
tester.view.devicePixelRatio = 1.0;
var composition =
(await tester.runAsync(() => FileLottie(asset).load()))!;

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