Compare commits
4 Commits
xha/text_t
...
v2.2.0
Author | SHA1 | Date | |
---|---|---|---|
dc43a532b0 | |||
1b752bf341 | |||
21f34e6334 | |||
8dcb052fe1 |
24
CHANGELOG.md
@ -1,3 +1,27 @@
|
|||||||
|
|
||||||
|
## [2.2.0]
|
||||||
|
Apply the latest fixes from Lottie-Android:
|
||||||
|
|
||||||
|
- Overhaul text layout
|
||||||
|
- Fix rounded corners modifying already rounded corners
|
||||||
|
- Support box position in Document Data
|
||||||
|
- Allow interpolating between gradients with different opacity stops
|
||||||
|
- Add support for gradient opacity stops
|
||||||
|
|
||||||
|
## [2.1.0]
|
||||||
|
- Improve the cache to ensure that there is not an empty frame each time we load an animation.
|
||||||
|
The method `AssetLottie('anim.json').load()` returns a `SynchronousFuture` if it has been loaded previously.
|
||||||
|
- Expose the `LottieCache` singleton.
|
||||||
|
It allows to change the cache behaviour and clear the entries.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
void main() {
|
||||||
|
Lottie.cache.maximumSize = 10;
|
||||||
|
Lottie.cache.clear();
|
||||||
|
Lottie.cache.evict(NetworkLottie('https://lottie.com/anim.json'));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## [2.0.0]
|
## [2.0.0]
|
||||||
- **Breaking change**: the lottie widget will be smaller if it relies on the intrinsic size of the composition.
|
- **Breaking change**: the lottie widget will be smaller if it relies on the intrinsic size of the composition.
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ linter:
|
|||||||
always_declare_return_types: true
|
always_declare_return_types: true
|
||||||
avoid_dynamic_calls: true
|
avoid_dynamic_calls: true
|
||||||
avoid_escaping_inner_quotes: true
|
avoid_escaping_inner_quotes: true
|
||||||
|
avoid_final_parameters: true
|
||||||
avoid_returning_null_for_future: true
|
avoid_returning_null_for_future: true
|
||||||
avoid_setters_without_getters: true
|
avoid_setters_without_getters: true
|
||||||
cancel_subscriptions: true
|
cancel_subscriptions: true
|
||||||
|
1
example/assets/Tests/BeyondBounds.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"v":"5.8.2","fr":23.9759979248047,"ip":0,"op":71.9999937681822,"w":400,"h":400,"nm":"BeyondBounds","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[510.547,510.547],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"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":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":71.9999937681822,"st":0,"bm":0}],"markers":[]}
|
BIN
example/assets/Tests/EmbeddedFont.zip
Normal file
1
example/assets/Tests/Framerate.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"v":"5.9.6","fr":3,"ip":0,"op":3,"w":200,"h":200,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[30,30,0],"to":[21.667,21.667,0],"ti":[-21.667,-21.667,0]},{"t":2,"s":[160,160,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[58.742,58.742],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3,"st":0,"ct":1,"bm":0}],"markers":[]}
|
1
example/assets/Tests/Heart.json
Normal file
1038
example/assets/Tests/InterpolateBetweenOpacityStops.json
Executable file
1
example/assets/Tests/LargeComposition.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"v":"5.8.1","fr":25,"ip":0,"op":2,"w":2000,"h":4000,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1000,2000,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[1554.562,597.062],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.220496237278,1,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1.281,-21.469],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[1780.188,3801.75],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.116727701823,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[2.094,12.875],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":2,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":1,"nm":"Red Solid 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1000,2000,0],"ix":2,"l":2},"a":{"a":0,"k":[1000,2000,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"sw":2000,"sh":4000,"sc":"#ff0000","ip":0,"op":2,"st":0,"bm":0}],"markers":[]}
|
1
example/assets/Tests/Multiline.json
Normal file
494
example/assets/Tests/OpacityStops.json
Normal file
@ -0,0 +1,494 @@
|
|||||||
|
{
|
||||||
|
"tgs": 1,
|
||||||
|
"v": "5.5.2",
|
||||||
|
"fr": 60,
|
||||||
|
"ip": 0,
|
||||||
|
"op": 180,
|
||||||
|
"w": 512,
|
||||||
|
"h": 512,
|
||||||
|
"nm": "02_ricl_klass - 3:00",
|
||||||
|
"ddd": 0,
|
||||||
|
"assets": [],
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"ddd": 0,
|
||||||
|
"ind": 6,
|
||||||
|
"ty": 4,
|
||||||
|
"parent": 5,
|
||||||
|
"sr": 1,
|
||||||
|
"ks": {
|
||||||
|
"o": {
|
||||||
|
"a": 1,
|
||||||
|
"k": [
|
||||||
|
{
|
||||||
|
"i": {
|
||||||
|
"x": [
|
||||||
|
0.833
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.833
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"x": [
|
||||||
|
0.167
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.167
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"t": -105,
|
||||||
|
"s": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"i": {
|
||||||
|
"x": [
|
||||||
|
0.833
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.833
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"x": [
|
||||||
|
0.167
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.167
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"t": -104,
|
||||||
|
"s": [
|
||||||
|
100
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"i": {
|
||||||
|
"x": [
|
||||||
|
0.833
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.833
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"x": [
|
||||||
|
0.167
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.167
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"t": 34,
|
||||||
|
"s": [
|
||||||
|
100
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"i": {
|
||||||
|
"x": [
|
||||||
|
0.833
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.833
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"x": [
|
||||||
|
0.167
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.167
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"t": 35,
|
||||||
|
"s": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"i": {
|
||||||
|
"x": [
|
||||||
|
0.833
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.833
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"x": [
|
||||||
|
0.167
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.167
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"t": 75,
|
||||||
|
"s": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"i": {
|
||||||
|
"x": [
|
||||||
|
0.833
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.833
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"x": [
|
||||||
|
0.167
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.167
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"t": 76,
|
||||||
|
"s": [
|
||||||
|
100
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"i": {
|
||||||
|
"x": [
|
||||||
|
0.833
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.833
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"x": [
|
||||||
|
0.167
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.167
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"t": 214,
|
||||||
|
"s": [
|
||||||
|
100
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"t": 215,
|
||||||
|
"s": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"p": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
0,
|
||||||
|
-0.031,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"a": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
-87,
|
||||||
|
-18.182,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"s": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
50,
|
||||||
|
33,
|
||||||
|
100
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ao": 0,
|
||||||
|
"shapes": [
|
||||||
|
{
|
||||||
|
"ty": "gr",
|
||||||
|
"it": [
|
||||||
|
{
|
||||||
|
"ind": 0,
|
||||||
|
"ty": "sh",
|
||||||
|
"ks": {
|
||||||
|
"a": 1,
|
||||||
|
"k": [
|
||||||
|
{
|
||||||
|
"i": {
|
||||||
|
"x": 0.833,
|
||||||
|
"y": 0.833
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"x": 0.167,
|
||||||
|
"y": 0.167
|
||||||
|
},
|
||||||
|
"t": 213,
|
||||||
|
"s": [
|
||||||
|
{
|
||||||
|
"i": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
[
|
||||||
|
571.25,
|
||||||
|
-298.22
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-192.5,
|
||||||
|
-267.902
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-182.875,
|
||||||
|
510.152
|
||||||
|
],
|
||||||
|
[
|
||||||
|
575.125,
|
||||||
|
547.848
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"c": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"t": 214,
|
||||||
|
"s": [
|
||||||
|
{
|
||||||
|
"i": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
[
|
||||||
|
122.25,
|
||||||
|
-242.159
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-192.5,
|
||||||
|
-267.902
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-181.875,
|
||||||
|
178.333
|
||||||
|
],
|
||||||
|
[
|
||||||
|
175.125,
|
||||||
|
141.788
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"c": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hd": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ty": "gf",
|
||||||
|
"o": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 100
|
||||||
|
},
|
||||||
|
"r": 1,
|
||||||
|
"bm": 0,
|
||||||
|
"g": {
|
||||||
|
"p": 5,
|
||||||
|
"k": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
0.832,
|
||||||
|
0.275,
|
||||||
|
0.89,
|
||||||
|
0.086,
|
||||||
|
|
||||||
|
0.86,
|
||||||
|
0.275,
|
||||||
|
0.89,
|
||||||
|
0.086,
|
||||||
|
|
||||||
|
0.887,
|
||||||
|
0.275,
|
||||||
|
0.89,
|
||||||
|
0.086,
|
||||||
|
|
||||||
|
0.944,
|
||||||
|
0.275,
|
||||||
|
0.89,
|
||||||
|
0.086,
|
||||||
|
|
||||||
|
1,
|
||||||
|
0.275,
|
||||||
|
0.89,
|
||||||
|
0.086,
|
||||||
|
|
||||||
|
0.65,
|
||||||
|
0,
|
||||||
|
|
||||||
|
0.785,
|
||||||
|
0.5,
|
||||||
|
|
||||||
|
0.84,
|
||||||
|
1,
|
||||||
|
|
||||||
|
0.862,
|
||||||
|
1,
|
||||||
|
|
||||||
|
0.885,
|
||||||
|
1,
|
||||||
|
|
||||||
|
0.896,
|
||||||
|
0.5,
|
||||||
|
|
||||||
|
0.908,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"s": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
457.898,
|
||||||
|
-71.143
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"e": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
-182.411,
|
||||||
|
-47.941
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"t": 2,
|
||||||
|
"h": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 0
|
||||||
|
},
|
||||||
|
"a": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 97.679
|
||||||
|
},
|
||||||
|
"hd": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ty": "tr",
|
||||||
|
"p": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"a": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"s": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
100,
|
||||||
|
100
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"r": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 0
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 100
|
||||||
|
},
|
||||||
|
"sk": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 0
|
||||||
|
},
|
||||||
|
"sa": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bm": 0,
|
||||||
|
"hd": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ip": 0,
|
||||||
|
"op": 180,
|
||||||
|
"st": -120,
|
||||||
|
"bm": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1
example/assets/Tests/PrecompBlurDecimapPrecompSize.json
Normal file
386
example/assets/Tests/RoundedWithAlreadyRoundedCorners.json
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
{
|
||||||
|
"v": "5.9.1",
|
||||||
|
"fr": 60,
|
||||||
|
"ip": 0,
|
||||||
|
"op": 56,
|
||||||
|
"w": 1080,
|
||||||
|
"h": 1080,
|
||||||
|
"nm": "Warning",
|
||||||
|
"ddd": 0,
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"id": "comp_0",
|
||||||
|
"nm": "Warning_2",
|
||||||
|
"fr": 60,
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"ddd": 0,
|
||||||
|
"ind": 3,
|
||||||
|
"ty": 4,
|
||||||
|
"nm": "CERCHIO contorni",
|
||||||
|
"sr": 1,
|
||||||
|
"ks": {
|
||||||
|
"o": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 100,
|
||||||
|
"ix": 11
|
||||||
|
},
|
||||||
|
"r": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 0,
|
||||||
|
"ix": 10
|
||||||
|
},
|
||||||
|
"p": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
24.5,
|
||||||
|
24.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"ix": 2,
|
||||||
|
"l": 2
|
||||||
|
},
|
||||||
|
"a": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
29.5,
|
||||||
|
29.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"ix": 1,
|
||||||
|
"l": 2
|
||||||
|
},
|
||||||
|
"s": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
100,
|
||||||
|
100,
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ix": 6,
|
||||||
|
"l": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ao": 0,
|
||||||
|
"shapes": [
|
||||||
|
{
|
||||||
|
"ty": "gr",
|
||||||
|
"it": [
|
||||||
|
{
|
||||||
|
"ind": 0,
|
||||||
|
"ty": "sh",
|
||||||
|
"ix": 1,
|
||||||
|
"ks": {
|
||||||
|
"a": 0,
|
||||||
|
"k": {
|
||||||
|
"i": [
|
||||||
|
[
|
||||||
|
-12.15,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
-12.15
|
||||||
|
],
|
||||||
|
[
|
||||||
|
12.15,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
12.15
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
[
|
||||||
|
12.15,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
12.15
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-12.15,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
-12.15
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
-22
|
||||||
|
],
|
||||||
|
[
|
||||||
|
22,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
22
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-22,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"c": true
|
||||||
|
},
|
||||||
|
"ix": 2
|
||||||
|
},
|
||||||
|
"nm": "Tracciato 1",
|
||||||
|
"mn": "ADBE Vector Shape - Group",
|
||||||
|
"hd": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ty": "st",
|
||||||
|
"c": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
0.956862804936,
|
||||||
|
0.290196078431,
|
||||||
|
0.239215701234,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"ix": 3
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 100,
|
||||||
|
"ix": 4
|
||||||
|
},
|
||||||
|
"w": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 3,
|
||||||
|
"ix": 5
|
||||||
|
},
|
||||||
|
"lc": 2,
|
||||||
|
"lj": 2,
|
||||||
|
"bm": 0,
|
||||||
|
"nm": "Traccia 1",
|
||||||
|
"mn": "ADBE Vector Graphic - Stroke",
|
||||||
|
"hd": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ty": "tr",
|
||||||
|
"p": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
29.5,
|
||||||
|
29.5
|
||||||
|
],
|
||||||
|
"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": "Gruppo 1",
|
||||||
|
"np": 2,
|
||||||
|
"cix": 2,
|
||||||
|
"bm": 0,
|
||||||
|
"ix": 1,
|
||||||
|
"mn": "ADBE Vector Group",
|
||||||
|
"hd": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ty": "tm",
|
||||||
|
"s": {
|
||||||
|
"a": 1,
|
||||||
|
"k": [
|
||||||
|
{
|
||||||
|
"i": {
|
||||||
|
"x": [
|
||||||
|
0.833
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.833
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"x": [
|
||||||
|
0.167
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.167
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"t": 0,
|
||||||
|
"s": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"t": 36,
|
||||||
|
"s": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ix": 1
|
||||||
|
},
|
||||||
|
"e": {
|
||||||
|
"a": 1,
|
||||||
|
"k": [
|
||||||
|
{
|
||||||
|
"i": {
|
||||||
|
"x": [
|
||||||
|
0.833
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.833
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"x": [
|
||||||
|
0.167
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
0.167
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"t": 0,
|
||||||
|
"s": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"t": 36,
|
||||||
|
"s": [
|
||||||
|
100
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ix": 2
|
||||||
|
},
|
||||||
|
"o": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 0,
|
||||||
|
"ix": 3
|
||||||
|
},
|
||||||
|
"m": 1,
|
||||||
|
"ix": 2,
|
||||||
|
"nm": "Taglia tracciati 1",
|
||||||
|
"mn": "ADBE Vector Filter - Trim",
|
||||||
|
"hd": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ty": "rd",
|
||||||
|
"nm": "Angoli arrotondati 1",
|
||||||
|
"r": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 10,
|
||||||
|
"ix": 1
|
||||||
|
},
|
||||||
|
"ix": 3,
|
||||||
|
"mn": "ADBE Vector Filter - RC",
|
||||||
|
"hd": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ip": 0,
|
||||||
|
"op": 57,
|
||||||
|
"st": 0,
|
||||||
|
"bm": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"ddd": 0,
|
||||||
|
"ind": 1,
|
||||||
|
"ty": 0,
|
||||||
|
"nm": "Warning_2",
|
||||||
|
"refId": "comp_0",
|
||||||
|
"sr": 1,
|
||||||
|
"ks": {
|
||||||
|
"o": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 100,
|
||||||
|
"ix": 11
|
||||||
|
},
|
||||||
|
"r": {
|
||||||
|
"a": 0,
|
||||||
|
"k": 0,
|
||||||
|
"ix": 10
|
||||||
|
},
|
||||||
|
"p": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
530,
|
||||||
|
530,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"ix": 2,
|
||||||
|
"l": 2
|
||||||
|
},
|
||||||
|
"a": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
24,
|
||||||
|
24,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"ix": 1,
|
||||||
|
"l": 2
|
||||||
|
},
|
||||||
|
"s": {
|
||||||
|
"a": 0,
|
||||||
|
"k": [
|
||||||
|
2000,
|
||||||
|
2000,
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ix": 6,
|
||||||
|
"l": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ao": 0,
|
||||||
|
"w": 48,
|
||||||
|
"h": 48,
|
||||||
|
"ip": 0,
|
||||||
|
"op": 57,
|
||||||
|
"st": 0,
|
||||||
|
"bm": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"markers": []
|
||||||
|
}
|
1
example/assets/Tests/SplitPathTransform.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"v":"5.7.4","fr":60,"ip":0,"op":63,"w":400,"h":400,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.984],"y":[0.777]},"o":{"x":[0.411],"y":[0.047]},"t":0,"s":[200]},{"t":62,"s":[460]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.926],"y":[0.943]},"o":{"x":[0.028],"y":[1.152]},"t":0,"s":[200]},{"t":62,"s":[460]}],"ix":4}},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[119.332,119.332],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-130.404,-126.932],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":63,"st":0,"bm":0}],"markers":[]}
|
2039
example/assets/Tests/TextWithPsCenter.json
Normal file
1626
example/assets/Tests/TextWithPsLeft.json
Normal file
1
example/assets/Tests/Thumb.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"v":"5.9.6","fr":29.9700012207031,"ip":0,"op":190.000007738859,"w":24,"h":24,"nm":"Thumb","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[12,12,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":0,"ix":5},"ir":{"a":0,"k":5,"ix":6},"is":{"a":0,"k":0,"ix":8},"or":{"a":0,"k":12,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.922702133656,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"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":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":190.000007738859,"st":0,"ct":1,"bm":0}],"markers":[]}
|
1
example/assets/Tests/TimeStretchAndStartOffset.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"v":"5.5.8","fr":60,"ip":0,"op":166,"w":828,"h":1215,"nm":"Залитые дуги 10 + opacity","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Sinie 2","td":1,"sr":1.53474205216067,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[413.199,607.88,0],"ix":2},"a":{"a":0,"k":[168.949,195.88,0],"ix":1},"s":{"a":0,"k":[207.219,207.219,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[11.998,6.913],[13.844,0.193],[-28.149,-0.401]],"o":[[-11.991,-6.921],[14.447,24.162],[-7.102,-11.886]],"v":[[5.137,-8.915],[-34.263,-19.764],[34.265,19.754]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-14.745,-25.464],[0.311,-0.18],[0.113,0],[14.745,25.466],[-0.31,0.179],[-0.114,0]],"o":[[29.425,0.007],[0.178,0.311],[-0.098,0.056],[-29.427,-0.005],[-0.179,-0.31],[0.099,-0.057],[0,0]],"v":[[-35.4,-21.063],[35.964,20.09],[35.725,20.977],[35.403,21.063],[-35.963,-20.09],[-35.725,-20.976],[-35.401,-21.063]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.894117706897,0,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[132.535,174.966],"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":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":48,"op":166,"st":-37.8760708166762,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Krug siniy 2","tt":1,"sr":0.98917079207921,"ks":{"o":{"a":0,"k":50,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[412.455,610.955,0],"ix":2},"a":{"a":0,"k":[135.603,464.717,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[0.252,0.252,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":55,"s":[0,0,100]},{"t":111.000102732441,"s":[79.385,79.385,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,105.185],[105.185,0],[0,-105.185],[-105.186,0]],"o":[[0,-105.185],[-105.186,0],[0,105.185],[105.185,0]],"v":[[190.455,0],[0,-190.455],[-190.455,0],[0,190.456]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[135.603,464.717],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[174.179,174.179],"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,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":48,"op":166,"st":25.2165841584158,"bm":0}],"markers":[]}
|
BIN
example/assets/Tests/ZipInlineImage.zip
Normal file
BIN
example/assets/Tests/anim_jpg.zip
Normal file
2492
example/assets/Tests/wile.json
Normal file
59
example/lib/examples/cache.dart
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lottie/lottie.dart';
|
||||||
|
|
||||||
|
void main() => runApp(const App());
|
||||||
|
|
||||||
|
class App extends StatelessWidget {
|
||||||
|
const App({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Scaffold(body: _Page()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Page extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
__PageState createState() => __PageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class __PageState extends State<_Page> {
|
||||||
|
var _animationKey = UniqueKey();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Lottie.network(
|
||||||
|
'https://assets10.lottiefiles.com/datafiles/QeC7XD39x4C1CIj/data.json',
|
||||||
|
key: _animationKey,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
width: 200,
|
||||||
|
height: 200,
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Lottie.cache.clear();
|
||||||
|
Lottie.cache.maximumSize = 10;
|
||||||
|
},
|
||||||
|
child: const Text('Clear cache'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
_animationKey = UniqueKey();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: const Text('Recreate animation'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ packages:
|
|||||||
name: archive
|
name: archive
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.2"
|
version: "3.3.5"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -43,6 +43,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.16.0"
|
version: "1.16.0"
|
||||||
|
convert:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.1"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -101,7 +108,7 @@ packages:
|
|||||||
name: golden_toolkit
|
name: golden_toolkit
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.13.0"
|
version: "0.14.0"
|
||||||
http:
|
http:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -116,6 +123,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
|
js:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: js
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.5"
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -136,7 +150,7 @@ packages:
|
|||||||
path: ".."
|
path: ".."
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "2.0.0"
|
version: "2.2.0"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -178,7 +192,7 @@ packages:
|
|||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.21"
|
version: "2.0.22"
|
||||||
path_provider_ios:
|
path_provider_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -228,6 +242,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.3"
|
version: "2.1.3"
|
||||||
|
pointycastle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pointycastle
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.6.2"
|
||||||
process:
|
process:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -302,7 +323,7 @@ packages:
|
|||||||
name: win32
|
name: win32
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.1"
|
version: "3.1.2"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -311,5 +332,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0+2"
|
version: "0.2.0+2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.18.0 <3.0.0"
|
dart: ">=2.18.4 <3.0.0"
|
||||||
flutter: ">=3.3.0"
|
flutter: ">=3.3.0"
|
||||||
|
@ -10,7 +10,7 @@ export 'src/options.dart' show LottieOptions;
|
|||||||
export 'src/providers/asset_provider.dart' show AssetLottie;
|
export 'src/providers/asset_provider.dart' show AssetLottie;
|
||||||
export 'src/providers/file_provider.dart' show FileLottie;
|
export 'src/providers/file_provider.dart' show FileLottie;
|
||||||
export 'src/providers/load_image.dart' show LottieImageProviderFactory;
|
export 'src/providers/load_image.dart' show LottieImageProviderFactory;
|
||||||
export 'src/providers/lottie_provider.dart' show LottieProvider;
|
export 'src/providers/lottie_provider.dart' show LottieProvider, LottieCache;
|
||||||
export 'src/providers/memory_provider.dart' show MemoryLottie;
|
export 'src/providers/memory_provider.dart' show MemoryLottie;
|
||||||
export 'src/providers/network_provider.dart' show NetworkLottie;
|
export 'src/providers/network_provider.dart' show NetworkLottie;
|
||||||
export 'src/raw_lottie.dart' show RawLottie;
|
export 'src/raw_lottie.dart' show RawLottie;
|
||||||
|
@ -52,8 +52,8 @@ class ContentGroup implements DrawingContent, PathContent, KeyPathElement {
|
|||||||
List<PathContent>? _pathContents;
|
List<PathContent>? _pathContents;
|
||||||
TransformKeyframeAnimation? _transformAnimation;
|
TransformKeyframeAnimation? _transformAnimation;
|
||||||
|
|
||||||
ContentGroup(final LottieDrawable lottieDrawable, BaseLayer layer,
|
ContentGroup(
|
||||||
ShapeGroup shapeGroup)
|
LottieDrawable lottieDrawable, BaseLayer layer, ShapeGroup shapeGroup)
|
||||||
: this.copy(
|
: this.copy(
|
||||||
lottieDrawable,
|
lottieDrawable,
|
||||||
layer,
|
layer,
|
||||||
|
@ -31,8 +31,8 @@ class GradientStrokeContent extends BaseStrokeContent {
|
|||||||
ValueCallbackKeyframeAnimation<List<Color>, List<Color>>?
|
ValueCallbackKeyframeAnimation<List<Color>, List<Color>>?
|
||||||
_colorCallbackAnimation;
|
_colorCallbackAnimation;
|
||||||
|
|
||||||
GradientStrokeContent(final LottieDrawable lottieDrawable, BaseLayer layer,
|
GradientStrokeContent(
|
||||||
GradientStroke stroke)
|
LottieDrawable lottieDrawable, BaseLayer layer, GradientStroke stroke)
|
||||||
: name = stroke.name,
|
: name = stroke.name,
|
||||||
_type = stroke.gradientType,
|
_type = stroke.gradientType,
|
||||||
_hidden = stroke.hidden,
|
_hidden = stroke.hidden,
|
||||||
|
@ -168,12 +168,12 @@ class RoundedCornersContent implements ShapeModifierContent {
|
|||||||
var previousCurveData = modifiedCurves[
|
var previousCurveData = modifiedCurves[
|
||||||
floorMod(modifiedCurvesIndex - 1, modifiedCurves.length)];
|
floorMod(modifiedCurvesIndex - 1, modifiedCurves.length)];
|
||||||
var currentCurveData = modifiedCurves[modifiedCurvesIndex];
|
var currentCurveData = modifiedCurves[modifiedCurvesIndex];
|
||||||
previousCurveData.controlPoint2 =
|
previousCurveData.controlPoint2 = Offset(
|
||||||
Offset(previousCurve.vertex.dx, previousCurve.vertex.dy);
|
previousCurve.controlPoint2.dx, previousCurve.controlPoint2.dy);
|
||||||
previousCurveData.vertex =
|
previousCurveData.vertex =
|
||||||
Offset(previousCurve.vertex.dx, previousCurve.vertex.dy);
|
Offset(previousCurve.vertex.dx, previousCurve.vertex.dy);
|
||||||
currentCurveData.controlPoint1 =
|
currentCurveData.controlPoint1 = Offset(
|
||||||
Offset(startingCurve.vertex.dx, startingCurve.vertex.dy);
|
startingCurve.controlPoint1.dx, startingCurve.controlPoint1.dy);
|
||||||
modifiedCurvesIndex++;
|
modifiedCurvesIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class StrokeContent extends BaseStrokeContent {
|
|||||||
BaseKeyframeAnimation<ColorFilter, ColorFilter?>? _colorFilterAnimation;
|
BaseKeyframeAnimation<ColorFilter, ColorFilter?>? _colorFilterAnimation;
|
||||||
|
|
||||||
StrokeContent(
|
StrokeContent(
|
||||||
final LottieDrawable lottieDrawable, BaseLayer layer, ShapeStroke stroke)
|
LottieDrawable lottieDrawable, BaseLayer layer, ShapeStroke stroke)
|
||||||
: name = stroke.name,
|
: name = stroke.name,
|
||||||
_hidden = stroke.hidden,
|
_hidden = stroke.hidden,
|
||||||
_colorAnimation = stroke.color.createAnimation(),
|
_colorAnimation = stroke.color.createAnimation(),
|
||||||
|
@ -62,6 +62,9 @@ class _DocumentDataValueCallback extends LottieValueCallback<DocumentData> {
|
|||||||
color: baseDocumentData.color,
|
color: baseDocumentData.color,
|
||||||
strokeColor: baseDocumentData.strokeColor,
|
strokeColor: baseDocumentData.strokeColor,
|
||||||
strokeWidth: baseDocumentData.strokeWidth,
|
strokeWidth: baseDocumentData.strokeWidth,
|
||||||
strokeOverFill: baseDocumentData.strokeOverFill);
|
strokeOverFill: baseDocumentData.strokeOverFill,
|
||||||
|
boxPosition: baseDocumentData.boxPosition,
|
||||||
|
boxSize: baseDocumentData.boxSize,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import '../lottie.dart';
|
|||||||
import 'composition.dart';
|
import 'composition.dart';
|
||||||
import 'l.dart';
|
import 'l.dart';
|
||||||
import 'lottie_builder.dart';
|
import 'lottie_builder.dart';
|
||||||
|
import 'providers/lottie_provider.dart';
|
||||||
|
|
||||||
/// A widget to display a loaded [LottieComposition].
|
/// A widget to display a loaded [LottieComposition].
|
||||||
/// The [controller] property allows to specify a custom AnimationController that
|
/// The [controller] property allows to specify a custom AnimationController that
|
||||||
@ -11,6 +12,9 @@ import 'lottie_builder.dart';
|
|||||||
/// automatically and the behavior could be adjusted with the properties [animate],
|
/// automatically and the behavior could be adjusted with the properties [animate],
|
||||||
/// [repeat] and [reverse].
|
/// [repeat] and [reverse].
|
||||||
class Lottie extends StatefulWidget {
|
class Lottie extends StatefulWidget {
|
||||||
|
/// The cache instance for recently loaded Lottie compositions.
|
||||||
|
static LottieCache get cache => sharedLottieCache;
|
||||||
|
|
||||||
const Lottie({
|
const Lottie({
|
||||||
super.key,
|
super.key,
|
||||||
required this.composition,
|
required this.composition,
|
||||||
|
@ -5,9 +5,22 @@ import 'lottie_drawable.dart';
|
|||||||
import 'lottie_image_asset.dart';
|
import 'lottie_image_asset.dart';
|
||||||
import 'value_delegate.dart';
|
import 'value_delegate.dart';
|
||||||
|
|
||||||
// TODO(xha): recognize style Bold, Medium, Regular, SemiBold, etc...
|
TextStyle defaultTextStyleDelegate(LottieFontStyle font) {
|
||||||
TextStyle defaultTextStyleDelegate(LottieFontStyle font) =>
|
var style = font.style.toLowerCase();
|
||||||
TextStyle(fontFamily: font.fontFamily);
|
|
||||||
|
var fontStyle = style.contains('italic') ? FontStyle.italic : null;
|
||||||
|
|
||||||
|
FontWeight? fontWeight;
|
||||||
|
if (style.contains('semibold') || style.contains('semi bold')) {
|
||||||
|
fontWeight = FontWeight.w600;
|
||||||
|
} else if (style.contains('bold')) {
|
||||||
|
fontWeight = FontWeight.bold;
|
||||||
|
}
|
||||||
|
return TextStyle(
|
||||||
|
fontFamily: font.fontFamily,
|
||||||
|
fontStyle: fontStyle,
|
||||||
|
fontWeight: fontWeight);
|
||||||
|
}
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class LottieDelegates {
|
class LottieDelegates {
|
||||||
|
@ -1,11 +1,57 @@
|
|||||||
import '../../animation/keyframe/gradient_color_keyframe_animation.dart';
|
import '../../animation/keyframe/gradient_color_keyframe_animation.dart';
|
||||||
|
import '../../value/keyframe.dart';
|
||||||
import '../content/gradient_color.dart';
|
import '../content/gradient_color.dart';
|
||||||
import 'base_animatable_value.dart';
|
import 'base_animatable_value.dart';
|
||||||
|
|
||||||
class AnimatableGradientColorValue
|
class AnimatableGradientColorValue
|
||||||
extends BaseAnimatableValue<GradientColor, GradientColor> {
|
extends BaseAnimatableValue<GradientColor, GradientColor> {
|
||||||
AnimatableGradientColorValue.fromKeyframes(super.keyframes)
|
AnimatableGradientColorValue.fromKeyframes(
|
||||||
: super.fromKeyframes();
|
List<Keyframe<GradientColor>> keyframes)
|
||||||
|
: super.fromKeyframes(_ensureInterpolatableKeyframes(keyframes));
|
||||||
|
|
||||||
|
static List<Keyframe<GradientColor>> _ensureInterpolatableKeyframes(
|
||||||
|
List<Keyframe<GradientColor>> keyframes) {
|
||||||
|
for (var i = 0; i < keyframes.length; i++) {
|
||||||
|
keyframes[i] = _ensureInterpolatableKeyframe(keyframes[i]);
|
||||||
|
}
|
||||||
|
return keyframes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Keyframe<GradientColor> _ensureInterpolatableKeyframe(
|
||||||
|
Keyframe<GradientColor> keyframe) {
|
||||||
|
var startValue = keyframe.startValue;
|
||||||
|
var endValue = keyframe.endValue;
|
||||||
|
if (startValue == null ||
|
||||||
|
endValue == null ||
|
||||||
|
startValue.positions.length == endValue.positions.length) {
|
||||||
|
return keyframe;
|
||||||
|
}
|
||||||
|
var mergedPositions =
|
||||||
|
_mergePositions(startValue.positions, endValue.positions);
|
||||||
|
// The start/end has opacity stops which required adding extra positions in between the existing colors.
|
||||||
|
return keyframe.copyWith(startValue.copyWithPositions(mergedPositions),
|
||||||
|
endValue.copyWithPositions(mergedPositions));
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<double> _mergePositions(
|
||||||
|
List<double> startPositions, List<double> endPositions) {
|
||||||
|
var mergedArray =
|
||||||
|
List<double>.filled(startPositions.length + endPositions.length, 0);
|
||||||
|
mergedArray.setRange(0, startPositions.length, startPositions);
|
||||||
|
mergedArray.setRange(startPositions.length,
|
||||||
|
startPositions.length + endPositions.length, endPositions);
|
||||||
|
mergedArray.sort();
|
||||||
|
var uniqueValues = 0;
|
||||||
|
var lastValue = double.nan;
|
||||||
|
for (var i = 0; i < mergedArray.length; i++) {
|
||||||
|
if (mergedArray[i] != lastValue) {
|
||||||
|
mergedArray[uniqueValues] = mergedArray[i];
|
||||||
|
uniqueValues++;
|
||||||
|
lastValue = mergedArray[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mergedArray.take(uniqueValues).toList();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
GradientColorKeyframeAnimation createAnimation() {
|
GradientColorKeyframeAnimation createAnimation() {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
import '../../utils/collection.dart';
|
||||||
import '../../utils/gamma_evaluator.dart';
|
import '../../utils/gamma_evaluator.dart';
|
||||||
|
|
||||||
class GradientColor {
|
class GradientColor {
|
||||||
@ -21,4 +22,33 @@ class GradientColor {
|
|||||||
GammaEvaluator.evaluate(progress, gc1.colors[i], gc2.colors[i]);
|
GammaEvaluator.evaluate(progress, gc1.colors[i], gc2.colors[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GradientColor copyWithPositions(List<double> positions) {
|
||||||
|
var colors = List<Color>.filled(positions.length, const Color(0x00000000));
|
||||||
|
for (var i = 0; i < positions.length; i++) {
|
||||||
|
colors[i] = _getColorForPosition(positions[i]);
|
||||||
|
}
|
||||||
|
return GradientColor(positions, colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color _getColorForPosition(double position) {
|
||||||
|
var existingIndex = binarySearch(positions, position);
|
||||||
|
if (existingIndex >= 0) {
|
||||||
|
return colors[existingIndex];
|
||||||
|
}
|
||||||
|
// binarySearch returns -insertionPoint - 1 if it is not found.
|
||||||
|
var insertionPoint = -(existingIndex + 1);
|
||||||
|
if (insertionPoint == 0) {
|
||||||
|
return colors[0];
|
||||||
|
} else if (insertionPoint == colors.length - 1) {
|
||||||
|
return colors[colors.length - 1];
|
||||||
|
}
|
||||||
|
var startPosition = positions[insertionPoint - 1];
|
||||||
|
var endPosition = positions[insertionPoint];
|
||||||
|
var startColor = colors[insertionPoint - 1];
|
||||||
|
var endColor = colors[insertionPoint];
|
||||||
|
|
||||||
|
var fraction = (position - startPosition) / (endPosition - startPosition);
|
||||||
|
return GammaEvaluator.evaluate(fraction, startColor, endColor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,16 @@ class DocumentData {
|
|||||||
final double size;
|
final double size;
|
||||||
final Justification justification;
|
final Justification justification;
|
||||||
final int tracking;
|
final int tracking;
|
||||||
|
|
||||||
|
/// Extra space in between lines. */
|
||||||
final double lineHeight;
|
final double lineHeight;
|
||||||
final double baselineShift;
|
final double baselineShift;
|
||||||
final Color color;
|
final Color color;
|
||||||
final Color strokeColor;
|
final Color strokeColor;
|
||||||
final double strokeWidth;
|
final double strokeWidth;
|
||||||
final bool strokeOverFill;
|
final bool strokeOverFill;
|
||||||
|
final Offset? boxPosition;
|
||||||
|
final Offset? boxSize;
|
||||||
|
|
||||||
DocumentData({
|
DocumentData({
|
||||||
required this.text,
|
required this.text,
|
||||||
@ -27,6 +31,8 @@ class DocumentData {
|
|||||||
required this.strokeColor,
|
required this.strokeColor,
|
||||||
required this.strokeWidth,
|
required this.strokeWidth,
|
||||||
required this.strokeOverFill,
|
required this.strokeOverFill,
|
||||||
|
required this.boxPosition,
|
||||||
|
required this.boxSize,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -42,7 +48,10 @@ class DocumentData {
|
|||||||
color,
|
color,
|
||||||
strokeColor,
|
strokeColor,
|
||||||
strokeWidth,
|
strokeWidth,
|
||||||
strokeOverFill);
|
strokeOverFill,
|
||||||
|
boxPosition,
|
||||||
|
boxSize,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -60,5 +69,7 @@ class DocumentData {
|
|||||||
color == other.color &&
|
color == other.color &&
|
||||||
strokeColor == other.strokeColor &&
|
strokeColor == other.strokeColor &&
|
||||||
strokeWidth == other.strokeWidth &&
|
strokeWidth == other.strokeWidth &&
|
||||||
strokeOverFill == other.strokeOverFill;
|
strokeOverFill == other.strokeOverFill &&
|
||||||
|
boxPosition == other.boxPosition &&
|
||||||
|
boxSize == other.boxSize;
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,7 @@ import 'content/shape_group.dart';
|
|||||||
|
|
||||||
class FontCharacter {
|
class FontCharacter {
|
||||||
static int hashFor(String character, String fontFamily, String style) {
|
static int hashFor(String character, String fontFamily, String style) {
|
||||||
var result = 0;
|
var result = character.hashCode;
|
||||||
result = 31 * result + character.hashCode;
|
|
||||||
result = 31 * result + fontFamily.hashCode;
|
result = 31 * result + fontFamily.hashCode;
|
||||||
result = 31 * result + style.hashCode;
|
result = 31 * result + style.hashCode;
|
||||||
return result;
|
return result;
|
||||||
|
@ -7,6 +7,7 @@ import '../../composition.dart';
|
|||||||
import '../../lottie_drawable.dart';
|
import '../../lottie_drawable.dart';
|
||||||
import '../../lottie_property.dart';
|
import '../../lottie_property.dart';
|
||||||
import '../../utils.dart';
|
import '../../utils.dart';
|
||||||
|
import '../../utils/characters.dart';
|
||||||
import '../../value/lottie_value_callback.dart';
|
import '../../value/lottie_value_callback.dart';
|
||||||
import '../document_data.dart';
|
import '../document_data.dart';
|
||||||
import '../font.dart';
|
import '../font.dart';
|
||||||
@ -21,6 +22,9 @@ class TextLayer extends BaseLayer {
|
|||||||
final _fillPaint = Paint()..style = PaintingStyle.fill;
|
final _fillPaint = Paint()..style = PaintingStyle.fill;
|
||||||
final _strokePaint = Paint()..style = PaintingStyle.stroke;
|
final _strokePaint = Paint()..style = PaintingStyle.stroke;
|
||||||
final _contentsForCharacter = <FontCharacter, List<ContentGroup>>{};
|
final _contentsForCharacter = <FontCharacter, List<ContentGroup>>{};
|
||||||
|
|
||||||
|
/// If this is paragraph text, one line may wrap depending on the size of the document data box.
|
||||||
|
final _textSubLines = <_TextSubLine>[];
|
||||||
final TextKeyframeAnimation _textAnimation;
|
final TextKeyframeAnimation _textAnimation;
|
||||||
final LottieComposition _composition;
|
final LottieComposition _composition;
|
||||||
|
|
||||||
@ -88,18 +92,26 @@ class TextLayer extends BaseLayer {
|
|||||||
@override
|
@override
|
||||||
void drawLayer(Canvas canvas, Size size, Matrix4 parentMatrix,
|
void drawLayer(Canvas canvas, Size size, Matrix4 parentMatrix,
|
||||||
{required int parentAlpha}) {
|
{required int parentAlpha}) {
|
||||||
canvas.save();
|
|
||||||
if (!lottieDrawable.useTextGlyphs) {
|
|
||||||
canvas.transform(parentMatrix.storage);
|
|
||||||
}
|
|
||||||
var documentData = _textAnimation.value;
|
var documentData = _textAnimation.value;
|
||||||
var font = _composition.fonts[documentData.fontName];
|
var font = _composition.fonts[documentData.fontName];
|
||||||
if (font == null) {
|
if (font == null) {
|
||||||
// Something is wrong.
|
|
||||||
canvas.restore();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
canvas.save();
|
||||||
|
canvas.transform(parentMatrix.storage);
|
||||||
|
|
||||||
|
_configurePaint(documentData, parentMatrix);
|
||||||
|
|
||||||
|
if (lottieDrawable.useTextGlyphs) {
|
||||||
|
_drawTextWithGlyphs(documentData, parentMatrix, font, canvas);
|
||||||
|
} else {
|
||||||
|
_drawTextWithFont(documentData, font, canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _configurePaint(DocumentData documentData, Matrix4 parentMatrix) {
|
||||||
Color fillPaintColor;
|
Color fillPaintColor;
|
||||||
if (_colorCallbackAnimation != null) {
|
if (_colorCallbackAnimation != null) {
|
||||||
fillPaintColor = _colorCallbackAnimation!.value;
|
fillPaintColor = _colorCallbackAnimation!.value;
|
||||||
@ -130,20 +142,11 @@ class TextLayer extends BaseLayer {
|
|||||||
} else if (_strokeWidthAnimation != null) {
|
} else if (_strokeWidthAnimation != null) {
|
||||||
_strokePaint.strokeWidth = _strokeWidthAnimation!.value;
|
_strokePaint.strokeWidth = _strokeWidthAnimation!.value;
|
||||||
} else {
|
} else {
|
||||||
var parentScale = parentMatrix.getScale();
|
_strokePaint.strokeWidth = documentData.strokeWidth;
|
||||||
_strokePaint.strokeWidth = documentData.strokeWidth * parentScale;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lottieDrawable.useTextGlyphs) {
|
void _drawTextWithGlyphs(DocumentData documentData, Matrix4 parentMatrix,
|
||||||
_drawTextGlyphs(documentData, parentMatrix, font, canvas);
|
|
||||||
} else {
|
|
||||||
_drawTextWithFont(documentData, font, parentMatrix, canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _drawTextGlyphs(DocumentData documentData, Matrix4 parentMatrix,
|
|
||||||
Font font, Canvas canvas) {
|
Font font, Canvas canvas) {
|
||||||
double textSize;
|
double textSize;
|
||||||
if (_textSizeCallbackAnimation != null) {
|
if (_textSizeCallbackAnimation != null) {
|
||||||
@ -157,73 +160,55 @@ class TextLayer extends BaseLayer {
|
|||||||
var parentScale = parentMatrix.getScale();
|
var parentScale = parentMatrix.getScale();
|
||||||
|
|
||||||
var text = documentData.text;
|
var text = documentData.text;
|
||||||
canvas.transform(parentMatrix.storage);
|
|
||||||
|
|
||||||
// Line height
|
|
||||||
var lineHeight = documentData.lineHeight;
|
|
||||||
|
|
||||||
// Split full text in multiple lines
|
// Split full text in multiple lines
|
||||||
var textLines = _getTextLines(text);
|
var textLines = _getTextLines(text);
|
||||||
var textLineCount = textLines.length;
|
var textLineCount = textLines.length;
|
||||||
for (var l = 0; l < textLineCount; l++) {
|
|
||||||
var textLine = textLines[l];
|
|
||||||
var textLineWidth =
|
|
||||||
_getTextLineWidthForGlyphs(textLine, font, fontScale, parentScale);
|
|
||||||
|
|
||||||
canvas.save();
|
|
||||||
|
|
||||||
// Apply horizontal justification
|
|
||||||
_applyJustification(documentData.justification, canvas, textLineWidth);
|
|
||||||
|
|
||||||
// Center text vertically
|
|
||||||
var multilineTranslateY = (textLineCount - 1) * lineHeight / 2;
|
|
||||||
var translateY = l * lineHeight - multilineTranslateY;
|
|
||||||
canvas.translate(0, translateY);
|
|
||||||
|
|
||||||
// Draw each line
|
|
||||||
_drawGlyphTextLine(textLine, documentData, Matrix4.identity(), font, canvas,
|
|
||||||
parentScale, fontScale);
|
|
||||||
|
|
||||||
// Reset canvas
|
|
||||||
canvas.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _drawGlyphTextLine(
|
|
||||||
String text,
|
|
||||||
DocumentData documentData,
|
|
||||||
Matrix4 parentMatrix,
|
|
||||||
Font font,
|
|
||||||
Canvas canvas,
|
|
||||||
double parentScale,
|
|
||||||
double fontScale) {
|
|
||||||
for (var i = 0; i < text.length; i++) {
|
|
||||||
var c = text[i];
|
|
||||||
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.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_drawCharacterAsGlyph(
|
|
||||||
character, parentMatrix, fontScale, documentData, canvas);
|
|
||||||
var tx = character.width * fontScale * parentScale;
|
|
||||||
// Add tracking
|
// Add tracking
|
||||||
var tracking = documentData.tracking / 10.0;
|
var tracking = documentData.tracking / 10;
|
||||||
if (_trackingCallbackAnimation != null) {
|
if (_trackingCallbackAnimation != null) {
|
||||||
tracking += _trackingCallbackAnimation!.value;
|
tracking += _trackingCallbackAnimation!.value;
|
||||||
} else if (_trackingAnimation != null) {
|
} else if (_trackingAnimation != null) {
|
||||||
tracking += _trackingAnimation!.value;
|
tracking += _trackingAnimation!.value;
|
||||||
}
|
}
|
||||||
tx += tracking * parentScale;
|
var lineIndex = -1;
|
||||||
|
for (var i = 0; i < textLineCount; i++) {
|
||||||
|
var textLine = textLines[i];
|
||||||
|
var boxWidth = documentData.boxSize?.dx ?? 0.0;
|
||||||
|
var lines = _splitGlyphTextIntoLines(
|
||||||
|
textLine, boxWidth, font, fontScale, tracking, null);
|
||||||
|
for (var j = 0; j < lines.length; j++) {
|
||||||
|
var line = lines[j];
|
||||||
|
lineIndex++;
|
||||||
|
|
||||||
|
canvas.save();
|
||||||
|
|
||||||
|
_offsetCanvas(canvas, documentData, lineIndex, line.width);
|
||||||
|
_drawGlyphTextLine(line.text, documentData, font, canvas, parentScale,
|
||||||
|
fontScale, tracking);
|
||||||
|
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 character = _composition.characters[characterHash];
|
||||||
|
if (character == null) {
|
||||||
|
// Something is wrong. Potentially, they didn't export the text as a glyph.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_drawCharacterAsGlyph(character, fontScale, documentData, canvas);
|
||||||
|
var tx = character.width * fontScale + tracking;
|
||||||
canvas.translate(tx, 0);
|
canvas.translate(tx, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _drawTextWithFont(DocumentData documentData, Font font,
|
void _drawTextWithFont(DocumentData documentData, Font font, Canvas canvas) {
|
||||||
Matrix4 parentMatrix, Canvas canvas) {
|
|
||||||
var textStyle = lottieDrawable.getTextStyle(font.family, font.style);
|
var textStyle = lottieDrawable.getTextStyle(font.family, font.style);
|
||||||
var text = documentData.text;
|
var text = documentData.text;
|
||||||
var textDelegate = lottieDrawable.delegates?.text;
|
var textDelegate = lottieDrawable.delegates?.text;
|
||||||
@ -240,9 +225,6 @@ class TextLayer extends BaseLayer {
|
|||||||
}
|
}
|
||||||
textStyle = textStyle.copyWith(fontSize: textSize);
|
textStyle = textStyle.copyWith(fontSize: textSize);
|
||||||
|
|
||||||
// Line height
|
|
||||||
var lineHeight = documentData.lineHeight;
|
|
||||||
|
|
||||||
// Calculate tracking
|
// Calculate tracking
|
||||||
var tracking = documentData.tracking / 10;
|
var tracking = documentData.tracking / 10;
|
||||||
if (_trackingCallbackAnimation != null) {
|
if (_trackingCallbackAnimation != null) {
|
||||||
@ -255,44 +237,60 @@ class TextLayer extends BaseLayer {
|
|||||||
// Split full text in multiple lines
|
// Split full text in multiple lines
|
||||||
var textLines = _getTextLines(text);
|
var textLines = _getTextLines(text);
|
||||||
var textLineCount = textLines.length;
|
var textLineCount = textLines.length;
|
||||||
for (var l = 0; l < textLineCount; l++) {
|
var lineIndex = -1;
|
||||||
var textLine = textLines[l];
|
for (var i = 0; i < textLineCount; i++) {
|
||||||
var textPainter = TextPainter(
|
var textLine = textLines[i];
|
||||||
text: TextSpan(text: textLine, style: textStyle),
|
var boxWidth = documentData.boxSize?.dx ?? 0.0;
|
||||||
textDirection: _textDirection);
|
var lines = _splitGlyphTextIntoLines(
|
||||||
textPainter.layout();
|
textLine, boxWidth, font, 0.0, tracking, textStyle);
|
||||||
var textLineWidth = textPainter.width;
|
for (var j = 0; j < lines.length; j++) {
|
||||||
// We have to manually add the tracking between characters as the strokePaint ignores it
|
var line = lines[j];
|
||||||
textLineWidth += (textLine.length - 1) * tracking;
|
lineIndex++;
|
||||||
|
|
||||||
canvas.save();
|
canvas.save();
|
||||||
|
|
||||||
// Apply horizontal justification
|
_offsetCanvas(canvas, documentData, lineIndex, line.width);
|
||||||
_applyJustification(documentData.justification, canvas, textLineWidth);
|
_drawFontTextLine(line.text, textStyle, documentData, canvas, tracking);
|
||||||
|
|
||||||
// Center text vertically
|
|
||||||
var multilineTranslateY = (textLineCount - 1) * lineHeight / 2;
|
|
||||||
var translateY = l * lineHeight - multilineTranslateY;
|
|
||||||
canvas.translate(0, translateY);
|
|
||||||
|
|
||||||
// Draw each line
|
|
||||||
_drawFontTextLine(textLine, textStyle, documentData, canvas, tracking);
|
|
||||||
|
|
||||||
// Reset canvas
|
|
||||||
canvas.restore();
|
canvas.restore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> _getTextLines(String text) {
|
|
||||||
// Split full text by carriage return character
|
|
||||||
var formattedText = text.replaceAll('\r\n', '\r').replaceAll('\n', '\r');
|
|
||||||
var textLinesArray = formattedText.split('\r');
|
|
||||||
return textLinesArray;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _drawFontTextLine(String text, TextStyle textStyle,
|
void _offsetCanvas(Canvas canvas, DocumentData documentData, int lineIndex,
|
||||||
|
double lineWidth) {
|
||||||
|
var position = documentData.boxPosition;
|
||||||
|
var size = documentData.boxSize;
|
||||||
|
var lineOffset = lineIndex * documentData.lineHeight;
|
||||||
|
var lineStart = position?.dx ?? 0.0;
|
||||||
|
var boxWidth = size?.dx ?? 0.0;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Characters> _getTextLines(String text) {
|
||||||
|
// Split full text by carriage return character
|
||||||
|
var formattedText = text
|
||||||
|
.replaceAll('\r\n', '\r')
|
||||||
|
.replaceAll('\u0003', '\r')
|
||||||
|
.replaceAll('\n', '\r');
|
||||||
|
var textLinesArray = formattedText.split('\r');
|
||||||
|
return textLinesArray.map((l) => l.characters).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawFontTextLine(Characters text, TextStyle textStyle,
|
||||||
DocumentData documentData, Canvas canvas, double tracking) {
|
DocumentData documentData, Canvas canvas, double tracking) {
|
||||||
for (var char in text.characters) {
|
for (var char in text) {
|
||||||
var charString = char;
|
var charString = char;
|
||||||
_drawCharacterFromFont(charString, textStyle, documentData, canvas);
|
_drawCharacterFromFont(charString, textStyle, documentData, canvas);
|
||||||
var textPainter = TextPainter(
|
var textPainter = TextPainter(
|
||||||
@ -305,43 +303,109 @@ class TextLayer extends BaseLayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double _getTextLineWidthForGlyphs(
|
List<_TextSubLine> _splitGlyphTextIntoLines(
|
||||||
String textLine, Font font, double fontScale, double parentScale) {
|
Characters textLine,
|
||||||
var textLineWidth = 0.0;
|
double boxWidth,
|
||||||
for (var i = 0; i < textLine.length; i++) {
|
Font font,
|
||||||
var c = textLine[i];
|
double fontScale,
|
||||||
|
double tracking,
|
||||||
|
TextStyle? textStyle) {
|
||||||
|
var usingGlyphs = textStyle == null;
|
||||||
|
var lineCount = 0;
|
||||||
|
|
||||||
|
var currentLineWidth = 0.0;
|
||||||
|
var currentLineStartIndex = 0;
|
||||||
|
|
||||||
|
var currentWordStartIndex = 0;
|
||||||
|
var currentWordWidth = 0.0;
|
||||||
|
var nextCharacterStartsWord = false;
|
||||||
|
|
||||||
|
// The measured size of a space.
|
||||||
|
var spaceWidth = 0.0;
|
||||||
|
|
||||||
|
var textPainter = TextPainter(
|
||||||
|
text: TextSpan(text: '', style: textStyle),
|
||||||
|
textDirection: _textDirection);
|
||||||
|
var i = 0;
|
||||||
|
for (var c in textLine) {
|
||||||
|
double currentCharWidth;
|
||||||
|
if (usingGlyphs) {
|
||||||
var characterHash = FontCharacter.hashFor(c, font.family, font.style);
|
var characterHash = FontCharacter.hashFor(c, font.family, font.style);
|
||||||
var character = _composition.characters[characterHash];
|
var character = _composition.characters[characterHash];
|
||||||
if (character == null) {
|
if (character == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
textLineWidth += character.width * fontScale * parentScale;
|
currentCharWidth = character.width * fontScale + tracking;
|
||||||
}
|
} else {
|
||||||
return textLineWidth;
|
textPainter.text = TextSpan(text: c, style: textStyle);
|
||||||
|
textPainter.layout();
|
||||||
|
currentCharWidth = textPainter.width + tracking;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _applyJustification(
|
if (c == ' ') {
|
||||||
Justification justification, Canvas canvas, double textLineWidth) {
|
spaceWidth = currentCharWidth;
|
||||||
switch (justification) {
|
nextCharacterStartsWord = true;
|
||||||
case Justification.leftAlign:
|
} else if (nextCharacterStartsWord) {
|
||||||
// Do nothing. Default is left aligned.
|
nextCharacterStartsWord = false;
|
||||||
break;
|
currentWordStartIndex = i;
|
||||||
case Justification.rightAlign:
|
currentWordWidth = currentCharWidth;
|
||||||
canvas.translate(-textLineWidth, 0);
|
} else {
|
||||||
break;
|
currentWordWidth += currentCharWidth;
|
||||||
case Justification.center:
|
|
||||||
canvas.translate(-textLineWidth / 2, 0);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
currentLineWidth += currentCharWidth;
|
||||||
|
|
||||||
|
if (boxWidth > 0 && currentLineWidth >= boxWidth) {
|
||||||
|
if (c == ' ') {
|
||||||
|
// Spaces at the end of a line don't do anything. Ignore it.
|
||||||
|
// The next non-space character will hit the conditions below.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var subLine = _ensureEnoughSubLines(++lineCount);
|
||||||
|
if (currentWordStartIndex == currentLineStartIndex) {
|
||||||
|
// Only word on line is wider than box, start wrapping mid-word.
|
||||||
|
var substr = textLine.getRange(currentLineStartIndex, i);
|
||||||
|
var trimmed = substr.trim(' '.characters);
|
||||||
|
var trimmedSpace = (trimmed.length - substr.length) * spaceWidth;
|
||||||
|
subLine.set(
|
||||||
|
trimmed, currentLineWidth - currentCharWidth - trimmedSpace);
|
||||||
|
currentLineStartIndex = i;
|
||||||
|
currentLineWidth = currentCharWidth;
|
||||||
|
currentWordStartIndex = currentLineStartIndex;
|
||||||
|
currentWordWidth = currentCharWidth;
|
||||||
|
} else {
|
||||||
|
var substr = textLine.getRange(
|
||||||
|
currentLineStartIndex, currentWordStartIndex - 1);
|
||||||
|
var trimmed = substr.trim(' '.characters);
|
||||||
|
var trimmedSpace = (substr.length - trimmed.length) * spaceWidth;
|
||||||
|
subLine.set(trimmed,
|
||||||
|
currentLineWidth - currentWordWidth - trimmedSpace - spaceWidth);
|
||||||
|
currentLineStartIndex = currentWordStartIndex;
|
||||||
|
currentLineWidth = currentWordWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if (currentLineWidth > 0) {
|
||||||
|
var line = _ensureEnoughSubLines(++lineCount);
|
||||||
|
line.set(textLine.getRange(currentLineStartIndex), currentLineWidth);
|
||||||
|
}
|
||||||
|
return _textSubLines.sublist(0, lineCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _drawCharacterAsGlyph(FontCharacter character, Matrix4 parentMatrix,
|
/// Elements are reused and not deleted to save allocations.
|
||||||
double fontScale, DocumentData documentData, Canvas canvas) {
|
_TextSubLine _ensureEnoughSubLines(int numLines) {
|
||||||
|
for (var i = _textSubLines.length; i < numLines; i++) {
|
||||||
|
_textSubLines.add(_TextSubLine());
|
||||||
|
}
|
||||||
|
return _textSubLines[numLines - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawCharacterAsGlyph(FontCharacter character, double fontScale,
|
||||||
|
DocumentData documentData, Canvas canvas) {
|
||||||
var contentGroups = _getContentsForCharacter(character);
|
var contentGroups = _getContentsForCharacter(character);
|
||||||
for (var j = 0; j < contentGroups.length; j++) {
|
for (var j = 0; j < contentGroups.length; j++) {
|
||||||
var path = contentGroups[j].getPath();
|
var path = contentGroups[j].getPath();
|
||||||
path.getBounds();
|
_matrix.reset();
|
||||||
_matrix.set(parentMatrix);
|
|
||||||
_matrix.translate(0.0, -documentData.baselineShift);
|
_matrix.translate(0.0, -documentData.baselineShift);
|
||||||
_matrix.scale(fontScale, fontScale);
|
_matrix.scale(fontScale, fontScale);
|
||||||
path = path.transform(_matrix.storage);
|
path = path.transform(_matrix.storage);
|
||||||
@ -489,3 +553,13 @@ class TextLayer extends BaseLayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _TextSubLine {
|
||||||
|
Characters text = Characters.empty;
|
||||||
|
double width = 0.0;
|
||||||
|
|
||||||
|
void set(Characters text, double width) {
|
||||||
|
this.text = text;
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -73,9 +73,7 @@ class AnimatableValueParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static List<Keyframe<T>> parse<T>(JsonReader reader,
|
static List<Keyframe<T>> parse<T>(JsonReader reader,
|
||||||
LottieComposition composition, ValueParser<T> valueParser,
|
LottieComposition composition, ValueParser<T> valueParser) {
|
||||||
{double? scale}) {
|
|
||||||
scale ??= 1.0;
|
|
||||||
return KeyframesParser.parse(reader, composition, valueParser);
|
return KeyframesParser.parse(reader, composition, valueParser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@ final JsonReaderOptions _names = JsonReaderOptions.of([
|
|||||||
'sc', // 8
|
'sc', // 8
|
||||||
'sw', // 9
|
'sw', // 9
|
||||||
'of', // 10
|
'of', // 10
|
||||||
|
'ps', // 11
|
||||||
|
'sz', // 12
|
||||||
]);
|
]);
|
||||||
|
|
||||||
DocumentData documentDataParser(JsonReader reader) {
|
DocumentData documentDataParser(JsonReader reader) {
|
||||||
@ -29,6 +31,8 @@ DocumentData documentDataParser(JsonReader reader) {
|
|||||||
var strokeColor = const Color(0x00000000);
|
var strokeColor = const Color(0x00000000);
|
||||||
var strokeWidth = 0.0;
|
var strokeWidth = 0.0;
|
||||||
var strokeOverFill = true;
|
var strokeOverFill = true;
|
||||||
|
Offset? boxPosition;
|
||||||
|
Offset? boxSize;
|
||||||
|
|
||||||
reader.beginObject();
|
reader.beginObject();
|
||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
@ -72,6 +76,16 @@ DocumentData documentDataParser(JsonReader reader) {
|
|||||||
case 10:
|
case 10:
|
||||||
strokeOverFill = reader.nextBoolean();
|
strokeOverFill = reader.nextBoolean();
|
||||||
break;
|
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:
|
default:
|
||||||
reader.skipName();
|
reader.skipName();
|
||||||
reader.skipValue();
|
reader.skipValue();
|
||||||
@ -90,5 +104,8 @@ DocumentData documentDataParser(JsonReader reader) {
|
|||||||
color: fillColor,
|
color: fillColor,
|
||||||
strokeColor: strokeColor,
|
strokeColor: strokeColor,
|
||||||
strokeWidth: strokeWidth,
|
strokeWidth: strokeWidth,
|
||||||
strokeOverFill: strokeOverFill);
|
strokeOverFill: strokeOverFill,
|
||||||
|
boxPosition: boxPosition,
|
||||||
|
boxSize: boxSize,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
import '../model/content/gradient_color.dart';
|
import '../model/content/gradient_color.dart';
|
||||||
|
import '../utils/collection.dart';
|
||||||
|
import '../utils/gamma_evaluator.dart';
|
||||||
import 'moshi/json_reader.dart';
|
import 'moshi/json_reader.dart';
|
||||||
|
|
||||||
class GradientColorParser {
|
class GradientColorParser {
|
||||||
@ -82,7 +84,7 @@ class GradientColorParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var gradientColor = GradientColor(positions, colors);
|
var gradientColor = GradientColor(positions, colors);
|
||||||
_addOpacityStopsToGradientIfNeeded(gradientColor, array);
|
gradientColor = _addOpacityStopsToGradientIfNeeded(gradientColor, array);
|
||||||
return gradientColor;
|
return gradientColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,50 +95,159 @@ class GradientColorParser {
|
|||||||
/// <p>
|
/// <p>
|
||||||
/// This should be a good approximation is nearly all cases. However, if there are many more
|
/// This should be a good approximation is nearly all cases. However, if there are many more
|
||||||
/// opacity stops than color stops, information will be lost.
|
/// opacity stops than color stops, information will be lost.
|
||||||
void _addOpacityStopsToGradientIfNeeded(
|
GradientColor _addOpacityStopsToGradientIfNeeded(
|
||||||
GradientColor gradientColor, List<double> array) {
|
GradientColor gradientColor, List<double> array) {
|
||||||
var startIndex = _colorPoints * 4;
|
var startIndex = _colorPoints * 4;
|
||||||
if (array.length <= startIndex) {
|
if (array.length <= startIndex) {
|
||||||
return;
|
return gradientColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When there are opacity stops, we create a merged list of color stops and opacity stops.
|
||||||
|
// For a given color stop, we linearly interpolate the opacity for the two opacity stops around it.
|
||||||
|
// For a given opacity stop, we linearly interpolate the color for the two color stops around it.
|
||||||
|
var colorStopPositions = gradientColor.positions;
|
||||||
|
var colorStopColors = gradientColor.colors;
|
||||||
|
|
||||||
var opacityStops = (array.length - startIndex) ~/ 2;
|
var opacityStops = (array.length - startIndex) ~/ 2;
|
||||||
var positions = List<double>.filled(opacityStops, 0.0);
|
var opacityStopPositions = List<double>.filled(opacityStops, 0.0);
|
||||||
var opacities = List<double>.filled(opacityStops, 0.0);
|
var opacityStopOpacities = List<double>.filled(opacityStops, 0.0);
|
||||||
|
|
||||||
for (var i = startIndex, j = 0; i < array.length; i++) {
|
for (var i = startIndex, j = 0; i < array.length; i++) {
|
||||||
if (i % 2 == 0) {
|
if (i % 2 == 0) {
|
||||||
positions[j] = array[i];
|
opacityStopPositions[j] = array[i];
|
||||||
} else {
|
} else {
|
||||||
opacities[j] = array[i];
|
opacityStopOpacities[j] = array[i];
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < gradientColor.size; i++) {
|
// Pre-SKIA (Oreo) devices render artifacts when there is two stops in the same position.
|
||||||
var color = gradientColor.colors[i];
|
// As a result, we have to de-dupe the merge color and opacity stop positions.
|
||||||
color = color.withAlpha(_getOpacityAtPosition(
|
var newPositions =
|
||||||
gradientColor.positions[i], positions, opacities));
|
mergeUniqueElements(gradientColor.positions, opacityStopPositions);
|
||||||
gradientColor.colors[i] = color;
|
var newColorPoints = newPositions.length;
|
||||||
|
var newColors = List<Color>.filled(newColorPoints, const Color(0xff000000));
|
||||||
|
|
||||||
|
for (var i = 0; i < newColorPoints; i++) {
|
||||||
|
var position = newPositions[i];
|
||||||
|
var colorStopIndex = binarySearch(colorStopPositions, position);
|
||||||
|
var opacityIndex = binarySearch(opacityStopPositions, position);
|
||||||
|
if (colorStopIndex < 0 || opacityIndex > 0) {
|
||||||
|
// This is a stop derived from an opacity stop.
|
||||||
|
if (opacityIndex < 0) {
|
||||||
|
// The formula here is derived from the return value for binarySearch. When an item isn't found, it returns -insertionPoint - 1.
|
||||||
|
opacityIndex = -(opacityIndex + 1);
|
||||||
|
}
|
||||||
|
newColors[i] = _getColorInBetweenColorStops(
|
||||||
|
position,
|
||||||
|
opacityStopOpacities[opacityIndex],
|
||||||
|
colorStopPositions,
|
||||||
|
colorStopColors);
|
||||||
|
} else {
|
||||||
|
// This os a step derived from a color stop.
|
||||||
|
newColors[i] = _getColorInBetweenOpacityStops(
|
||||||
|
position,
|
||||||
|
colorStopColors[colorStopIndex],
|
||||||
|
opacityStopPositions,
|
||||||
|
opacityStopOpacities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GradientColor(newPositions, newColors);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color _getColorInBetweenColorStops(double position, double opacity,
|
||||||
|
List<double> colorStopPositions, List<Color> colorStopColors) {
|
||||||
|
if (colorStopColors.length < 2 || position == colorStopPositions[0]) {
|
||||||
|
return colorStopColors[0];
|
||||||
|
}
|
||||||
|
for (var i = 1; i < colorStopPositions.length; i++) {
|
||||||
|
var colorStopPosition = colorStopPositions[i];
|
||||||
|
if (colorStopPosition < position && i != colorStopPositions.length - 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// We found the position in which position is between i - 1 and i.
|
||||||
|
var distanceBetweenColors =
|
||||||
|
colorStopPositions[i] - colorStopPositions[i - 1];
|
||||||
|
var distanceToLowerColor = position - colorStopPositions[i - 1];
|
||||||
|
var percentage = distanceToLowerColor / distanceBetweenColors;
|
||||||
|
var upperColor = colorStopColors[i];
|
||||||
|
var lowerColor = colorStopColors[i - 1];
|
||||||
|
return GammaEvaluator.evaluate(
|
||||||
|
percentage, upperColor.withOpacity(1), lowerColor.withOpacity(1))
|
||||||
|
.withOpacity(opacity);
|
||||||
|
}
|
||||||
|
throw Exception('Unreachable code.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Color _getColorInBetweenOpacityStops(double position, Color color,
|
||||||
|
List<double> opacityStopPositions, List<double> opacityStopOpacities) {
|
||||||
|
if (opacityStopOpacities.length < 2 ||
|
||||||
|
position <= opacityStopPositions[0]) {
|
||||||
|
return color.withOpacity(opacityStopOpacities[0]);
|
||||||
|
}
|
||||||
|
for (var i = 1; i < opacityStopPositions.length; i++) {
|
||||||
|
var opacityStopPosition = opacityStopPositions[i];
|
||||||
|
if (opacityStopPosition < position &&
|
||||||
|
i != opacityStopPositions.length - 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final double opacity;
|
||||||
|
if (opacityStopPosition <= position) {
|
||||||
|
opacity = opacityStopOpacities[i];
|
||||||
|
} else {
|
||||||
|
// We found the position in which position in between i - 1 and i.
|
||||||
|
var distanceBetweenOpacities =
|
||||||
|
opacityStopPositions[i] - opacityStopPositions[i - 1];
|
||||||
|
var distanceToLowerOpacity = position - opacityStopPositions[i - 1];
|
||||||
|
var percentage = distanceToLowerOpacity / distanceBetweenOpacities;
|
||||||
|
opacity = lerpDouble(
|
||||||
|
opacityStopOpacities[i - 1], opacityStopOpacities[i], percentage)!;
|
||||||
|
}
|
||||||
|
return color.withOpacity(opacity);
|
||||||
|
}
|
||||||
|
throw Exception('Unreachable code.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes two sorted float arrays and merges their elements while removing duplicates.
|
||||||
|
static List<double> mergeUniqueElements(
|
||||||
|
List<double> arrayA, List<double> arrayB) {
|
||||||
|
if (arrayA.isEmpty) {
|
||||||
|
return arrayB;
|
||||||
|
} else if (arrayB.isEmpty) {
|
||||||
|
return arrayA;
|
||||||
|
}
|
||||||
|
|
||||||
|
var aIndex = 0;
|
||||||
|
var bIndex = 0;
|
||||||
|
var numDuplicates = 0;
|
||||||
|
// This will be the merged list but may be longer than what is needed if there are duplicates.
|
||||||
|
// If there are, the 0 elements at the end need to be truncated.
|
||||||
|
var mergedNotTruncated =
|
||||||
|
List<double>.filled(arrayA.length + arrayB.length, 0);
|
||||||
|
for (var i = 0; i < mergedNotTruncated.length; i++) {
|
||||||
|
final a = aIndex < arrayA.length ? arrayA[aIndex] : double.nan;
|
||||||
|
final b = bIndex < arrayB.length ? arrayB[bIndex] : double.nan;
|
||||||
|
|
||||||
|
if (b.isNaN || a < b) {
|
||||||
|
mergedNotTruncated[i] = a;
|
||||||
|
aIndex++;
|
||||||
|
} else if (a.isNaN || b < a) {
|
||||||
|
mergedNotTruncated[i] = b;
|
||||||
|
bIndex++;
|
||||||
|
} else {
|
||||||
|
mergedNotTruncated[i] = a;
|
||||||
|
aIndex++;
|
||||||
|
bIndex++;
|
||||||
|
numDuplicates++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int _getOpacityAtPosition(
|
if (numDuplicates == 0) {
|
||||||
double position, List<double> positions, List<double> opacities) {
|
return mergedNotTruncated;
|
||||||
for (var i = 1; i < positions.length; i++) {
|
|
||||||
var lastPosition = positions[i - 1];
|
|
||||||
var thisPosition = positions[i];
|
|
||||||
if (positions[i] >= position) {
|
|
||||||
var progress =
|
|
||||||
(position - lastPosition) / (thisPosition - lastPosition);
|
|
||||||
progress = progress.clamp(0, 1);
|
|
||||||
if (progress.isNaN) {
|
|
||||||
progress = 0.0;
|
|
||||||
}
|
}
|
||||||
return (255 * lerpDouble(opacities[i - 1], opacities[i], progress)!)
|
|
||||||
.round();
|
return mergedNotTruncated
|
||||||
}
|
.take(mergedNotTruncated.length - numDuplicates)
|
||||||
}
|
.toList();
|
||||||
return (255 * opacities[opacities.length - 1]).round();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,8 @@ class AssetLottie extends LottieProvider {
|
|||||||
final String? package;
|
final String? package;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LottieComposition> load() async {
|
Future<LottieComposition> load() {
|
||||||
var cacheKey = 'asset-$keyName-$bundle';
|
return sharedLottieCache.putIfAbsent(this, () async {
|
||||||
return sharedLottieCache.putIfAbsent(cacheKey, () async {
|
|
||||||
final chosenBundle = bundle ?? rootBundle;
|
final chosenBundle = bundle ?? rootBundle;
|
||||||
|
|
||||||
var data = await chosenBundle.load(keyName);
|
var data = await chosenBundle.load(keyName);
|
||||||
|
@ -12,9 +12,8 @@ class FileLottie extends LottieProvider {
|
|||||||
final Object /*io.File|html.File*/ file;
|
final Object /*io.File|html.File*/ file;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LottieComposition> load() async {
|
Future<LottieComposition> load() {
|
||||||
var cacheKey = 'file-${io.filePath(file)}';
|
return sharedLottieCache.putIfAbsent(this, () async {
|
||||||
return sharedLottieCache.putIfAbsent(cacheKey, () async {
|
|
||||||
var bytes = await io.loadFile(file);
|
var bytes = await io.loadFile(file);
|
||||||
var composition = await LottieComposition.fromBytes(bytes,
|
var composition = await LottieComposition.fromBytes(bytes,
|
||||||
name: p.basenameWithoutExtension(io.filePath(file)),
|
name: p.basenameWithoutExtension(io.filePath(file)),
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import '../../lottie.dart';
|
import '../../lottie.dart';
|
||||||
import 'load_image.dart';
|
import 'load_image.dart';
|
||||||
|
|
||||||
@ -19,37 +20,103 @@ abstract class LottieProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class LottieCache {
|
class LottieCache {
|
||||||
final int maximumSize;
|
final Map<Object, Future<LottieComposition>> _pending =
|
||||||
final _cache = <String, Future<LottieComposition>>{};
|
<Object, Future<LottieComposition>>{};
|
||||||
|
final Map<Object, LottieComposition> _cache = <Object, LottieComposition>{};
|
||||||
|
|
||||||
LottieCache({int? maximumSize}) : maximumSize = maximumSize ?? 1000;
|
/// Maximum number of entries to store in the cache.
|
||||||
|
///
|
||||||
|
/// Once this many entries have been cached, the least-recently-used entry is
|
||||||
|
/// evicted when adding a new entry.
|
||||||
|
int get maximumSize => _maximumSize;
|
||||||
|
int _maximumSize = 1000;
|
||||||
|
|
||||||
Future<LottieComposition> putIfAbsent(
|
/// Changes the maximum cache size.
|
||||||
String key, Future<LottieComposition> Function() load) {
|
///
|
||||||
var composition = _cache[key];
|
/// If the new size is smaller than the current number of elements, the
|
||||||
if (composition != null) {
|
/// extraneous elements are evicted immediately. Setting this to zero and then
|
||||||
// Remove it so that we add it in front of the cache to prevent evicted
|
/// returning it to its original value will therefore immediately clear the
|
||||||
_cache.remove(key);
|
/// cache.
|
||||||
|
set maximumSize(int value) {
|
||||||
|
assert(value >= 0);
|
||||||
|
if (value == maximumSize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_maximumSize = value;
|
||||||
|
if (maximumSize == 0) {
|
||||||
|
clear();
|
||||||
} else {
|
} else {
|
||||||
composition = load();
|
|
||||||
}
|
|
||||||
|
|
||||||
_cache[key] = composition;
|
|
||||||
|
|
||||||
_checkCacheSize();
|
|
||||||
|
|
||||||
return composition;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _checkCacheSize() {
|
|
||||||
while (_cache.length > maximumSize) {
|
while (_cache.length > maximumSize) {
|
||||||
_cache.remove(_cache.keys.first);
|
_cache.remove(_cache.keys.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Evicts all entries from the cache.
|
||||||
|
///
|
||||||
|
/// This is useful if, for instance, the root asset bundle has been updated
|
||||||
|
/// and therefore new images must be obtained.
|
||||||
void clear() {
|
void clear() {
|
||||||
_cache.clear();
|
_cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evicts a single entry from the cache, returning true if successful.
|
||||||
|
bool evict(Object key) {
|
||||||
|
return _cache.remove(key) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the previously cached [LottieComposition] for the given key, if available;
|
||||||
|
/// if not, calls the given callback to obtain it first. In either case, the
|
||||||
|
/// key is moved to the "most recently used" position.
|
||||||
|
///
|
||||||
|
/// The arguments must not be null. The `loader` cannot return null.
|
||||||
|
Future<LottieComposition> putIfAbsent(
|
||||||
|
Object key,
|
||||||
|
Future<LottieComposition> Function() loader,
|
||||||
|
) {
|
||||||
|
var pendingResult = _pending[key];
|
||||||
|
if (pendingResult != null) {
|
||||||
|
return pendingResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = _cache[key];
|
||||||
|
if (result != null) {
|
||||||
|
// Remove the provider from the list so that we can put it back in below
|
||||||
|
// and thus move it to the end of the list.
|
||||||
|
_cache.remove(key);
|
||||||
|
} else {
|
||||||
|
if (_cache.length == maximumSize && maximumSize > 0) {
|
||||||
|
_cache.remove(_cache.keys.first);
|
||||||
|
}
|
||||||
|
pendingResult = loader();
|
||||||
|
_pending[key] = pendingResult;
|
||||||
|
pendingResult.then<void>((LottieComposition data) {
|
||||||
|
_pending.remove(key);
|
||||||
|
_add(key, data);
|
||||||
|
|
||||||
|
result = data; // in case it was a synchronous future.
|
||||||
|
}).catchError((Object? e) {
|
||||||
|
_pending.remove(key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (result != null) {
|
||||||
|
_add(key, result!);
|
||||||
|
return SynchronousFuture<LottieComposition>(result!);
|
||||||
|
}
|
||||||
|
assert(_cache.length <= maximumSize);
|
||||||
|
return pendingResult!;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _add(Object key, LottieComposition result) {
|
||||||
|
if (maximumSize > 0) {
|
||||||
|
assert(_cache.length < maximumSize);
|
||||||
|
_cache[key] = result;
|
||||||
|
}
|
||||||
|
assert(_cache.length <= maximumSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The number of entries in the cache.
|
||||||
|
int get count => _cache.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
final sharedLottieCache = LottieCache();
|
final sharedLottieCache = LottieCache();
|
||||||
|
@ -13,10 +13,8 @@ class MemoryLottie extends LottieProvider {
|
|||||||
final Uint8List bytes;
|
final Uint8List bytes;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LottieComposition> load() async {
|
Future<LottieComposition> load() {
|
||||||
// TODO(xha): hash the list content
|
return sharedLottieCache.putIfAbsent(this, () async {
|
||||||
var cacheKey = 'memory-${bytes.hashCode}-${bytes.lengthInBytes}';
|
|
||||||
return sharedLottieCache.putIfAbsent(cacheKey, () async {
|
|
||||||
var composition = await LottieComposition.fromBytes(bytes,
|
var composition = await LottieComposition.fromBytes(bytes,
|
||||||
imageProviderFactory: imageProviderFactory);
|
imageProviderFactory: imageProviderFactory);
|
||||||
for (var image in composition.images.values) {
|
for (var image in composition.images.values) {
|
||||||
@ -40,6 +38,8 @@ class MemoryLottie extends LottieProvider {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(dynamic other) {
|
bool operator ==(dynamic other) {
|
||||||
if (other.runtimeType != runtimeType) return false;
|
if (other.runtimeType != runtimeType) return false;
|
||||||
|
|
||||||
|
//TODO(xha): compare bytes content
|
||||||
return other is MemoryLottie && other.bytes == bytes;
|
return other is MemoryLottie && other.bytes == bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,9 +15,8 @@ class NetworkLottie extends LottieProvider {
|
|||||||
final Map<String, String>? headers;
|
final Map<String, String>? headers;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LottieComposition> load() async {
|
Future<LottieComposition> load() {
|
||||||
var cacheKey = 'network-$url';
|
return sharedLottieCache.putIfAbsent(this, () async {
|
||||||
return sharedLottieCache.putIfAbsent(cacheKey, () async {
|
|
||||||
var resolved = Uri.base.resolve(url);
|
var resolved = Uri.base.resolve(url);
|
||||||
var bytes = await network.loadHttp(resolved, headers: headers);
|
var bytes = await network.loadHttp(resolved, headers: headers);
|
||||||
|
|
||||||
|
27
lib/src/utils/characters.dart
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
extension CharactersExtension on Characters {
|
||||||
|
Characters trimTrailing(Characters pattern) {
|
||||||
|
if (pattern.isEmpty) return this;
|
||||||
|
|
||||||
|
var i = length;
|
||||||
|
while (i >= pattern.length && getRange(i - pattern.length, i) == pattern) {
|
||||||
|
i -= pattern.length;
|
||||||
|
}
|
||||||
|
return getRange(0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Characters trimLeading(Characters pattern) {
|
||||||
|
if (pattern.isEmpty) return this;
|
||||||
|
var i = 0;
|
||||||
|
while (i <= length - pattern.length &&
|
||||||
|
getRange(i, i + pattern.length) == pattern) {
|
||||||
|
i += pattern.length;
|
||||||
|
}
|
||||||
|
return getRange(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Characters trim(Characters pattern) {
|
||||||
|
return trimLeading(pattern).trimTrailing(pattern);
|
||||||
|
}
|
||||||
|
}
|
61
lib/src/utils/collection.dart
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/// Returns a position of the [value] in [sortedList], if it is there.
|
||||||
|
///
|
||||||
|
/// If the list isn't sorted according to the [compare] function, the result
|
||||||
|
/// is unpredictable.
|
||||||
|
///
|
||||||
|
/// If [compare] is omitted, this defaults to calling [Comparable.compareTo] on
|
||||||
|
/// the objects. In this case, the objects must be [Comparable].
|
||||||
|
///
|
||||||
|
/// Returns -1 if [value] is not in the list.
|
||||||
|
int binarySearch<E>(List<E> sortedList, E value,
|
||||||
|
{int Function(E, E)? compare}) {
|
||||||
|
compare ??= defaultCompare;
|
||||||
|
return binarySearchBy<E, E>(sortedList, identity, compare, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a position of the [value] in [sortedList], if it is there.
|
||||||
|
///
|
||||||
|
/// If the list isn't sorted according to the [compare] function on the [keyOf]
|
||||||
|
/// property of the elements, the result is unpredictable.
|
||||||
|
///
|
||||||
|
/// Returns -1 if [value] is not in the list by default.
|
||||||
|
///
|
||||||
|
/// If [start] and [end] are supplied, only that range is searched,
|
||||||
|
/// and only that range need to be sorted.
|
||||||
|
int binarySearchBy<E, K>(List<E> sortedList, K Function(E element) keyOf,
|
||||||
|
int Function(K, K) compare, E value,
|
||||||
|
[int start = 0, int? end]) {
|
||||||
|
end = RangeError.checkValidRange(start, end, sortedList.length);
|
||||||
|
var min = start;
|
||||||
|
var max = end;
|
||||||
|
var key = keyOf(value);
|
||||||
|
while (min < max) {
|
||||||
|
var mid = min + ((max - min) >> 1);
|
||||||
|
var element = sortedList[mid];
|
||||||
|
var comp = compare(keyOf(element), key);
|
||||||
|
if (comp == 0) return mid;
|
||||||
|
if (comp < 0) {
|
||||||
|
min = mid + 1;
|
||||||
|
} else {
|
||||||
|
max = mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [Comparator] that asserts that its first argument is comparable.
|
||||||
|
///
|
||||||
|
/// The function behaves just like [List.sort]'s
|
||||||
|
/// default comparison function. It is entirely dynamic in its testing.
|
||||||
|
///
|
||||||
|
/// Should be used when optimistically comparing object that are assumed
|
||||||
|
/// to be comparable.
|
||||||
|
/// If the elements are known to be comparable, use [compareComparable].
|
||||||
|
int defaultCompare(Object? value1, Object? value2) =>
|
||||||
|
(value1! as Comparable<Object?>).compareTo(value2);
|
||||||
|
|
||||||
|
/// A reusable identity function at any type.
|
||||||
|
T identity<T>(T value) => value;
|
||||||
|
|
||||||
|
/// A reusable typed comparable comparator.
|
||||||
|
int compareComparable<T extends Comparable<T>>(T a, T b) => a.compareTo(b);
|
@ -40,6 +40,18 @@ class Keyframe<T> {
|
|||||||
xInterpolator = null,
|
xInterpolator = null,
|
||||||
yInterpolator = null;
|
yInterpolator = null;
|
||||||
|
|
||||||
|
Keyframe._(this.startValue, this.endValue)
|
||||||
|
: _composition = null,
|
||||||
|
interpolator = null,
|
||||||
|
xInterpolator = null,
|
||||||
|
yInterpolator = null,
|
||||||
|
startFrame = double.minPositive,
|
||||||
|
endFrame = double.maxFinite;
|
||||||
|
|
||||||
|
Keyframe<T> copyWith(T startValue, T endValue) {
|
||||||
|
return Keyframe<T>._(startValue, endValue);
|
||||||
|
}
|
||||||
|
|
||||||
double get startProgress {
|
double get startProgress {
|
||||||
if (_composition == null) {
|
if (_composition == null) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
187
pubspec.lock
@ -21,7 +21,7 @@ packages:
|
|||||||
name: archive
|
name: archive
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.2"
|
version: "3.3.5"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -43,62 +43,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
build:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: build
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.3.1"
|
|
||||||
build_config:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: build_config
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.1"
|
|
||||||
build_daemon:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: build_daemon
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.1.0"
|
|
||||||
build_resolvers:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: build_resolvers
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.0"
|
|
||||||
build_runner:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description:
|
|
||||||
name: build_runner
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.3.2"
|
|
||||||
build_runner_core:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: build_runner_core
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "7.2.7"
|
|
||||||
built_collection:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: built_collection
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "5.1.1"
|
|
||||||
built_value:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: built_value
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "8.4.2"
|
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -106,13 +50,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.1"
|
version: "1.2.1"
|
||||||
checked_yaml:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: checked_yaml
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.1"
|
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -120,13 +57,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
code_builder:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: code_builder
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "4.3.0"
|
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -169,13 +99,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.4"
|
version: "6.1.4"
|
||||||
fixnum:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: fixnum
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.1"
|
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -193,13 +116,6 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
frontend_server_client:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: frontend_server_client
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.1.0"
|
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -207,34 +123,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
graphs:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: graphs
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.2.0"
|
|
||||||
http_multi_server:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: http_multi_server
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "3.2.1"
|
|
||||||
http_parser:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: http_parser
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "4.0.2"
|
|
||||||
io:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: io
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.3"
|
|
||||||
js:
|
js:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -242,13 +130,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.5"
|
version: "0.6.5"
|
||||||
json_annotation:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: json_annotation
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "4.7.0"
|
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -256,13 +137,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.1"
|
||||||
logging:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: logging
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.0"
|
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -284,13 +158,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0"
|
version: "1.8.0"
|
||||||
mime:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: mime
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.2"
|
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -305,41 +172,20 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.2"
|
version: "1.8.2"
|
||||||
pool:
|
pointycastle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pool
|
name: pointycastle
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.1"
|
version: "3.6.2"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: "direct dev"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pub_semver
|
name: pub_semver
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.3"
|
||||||
pubspec_parse:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: pubspec_parse
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.1"
|
|
||||||
shelf:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shelf
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.4.0"
|
|
||||||
shelf_web_socket:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shelf_web_socket
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.3"
|
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -366,13 +212,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
stream_transform:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: stream_transform
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.0"
|
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -394,13 +233,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.12"
|
version: "0.4.12"
|
||||||
timing:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: timing
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.0"
|
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -422,13 +254,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "1.0.2"
|
||||||
web_socket_channel:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: web_socket_channel
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.2.0"
|
|
||||||
yaml:
|
yaml:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
name: lottie
|
name: lottie
|
||||||
description: Render After Effects animations natively on Flutter. This package is a pure Dart implementation of a Lottie player.
|
description: Render After Effects animations natively on Flutter. This package is a pure Dart implementation of a Lottie player.
|
||||||
version: 2.0.0
|
version: 2.2.0
|
||||||
repository: https://github.com/xvrh/lottie-flutter
|
repository: https://github.com/xvrh/lottie-flutter
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
@ -16,10 +16,8 @@ dependencies:
|
|||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
analyzer:
|
analyzer:
|
||||||
build_runner:
|
|
||||||
dart_style:
|
dart_style:
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
pub_semver:
|
|
||||||
yaml:
|
yaml:
|
||||||
|
35
test/characters_test.dart
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:lottie/src/utils/characters.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('TrimTrailing characters', () {
|
||||||
|
expect('ab c d '.characters.trimTrailing(' '.characters),
|
||||||
|
'ab c d'.characters);
|
||||||
|
expect(' '.characters.trimTrailing(' '.characters), ''.characters);
|
||||||
|
expect(' a '.characters.trimTrailing(' '.characters), ' a'.characters);
|
||||||
|
expect(' aa'.characters.trimTrailing('a'.characters), ' '.characters);
|
||||||
|
expect('aabcbc'.characters.trimTrailing('bc'.characters), 'aa'.characters);
|
||||||
|
expect('bcbc'.characters.trimTrailing('bc'.characters), ''.characters);
|
||||||
|
expect(''.characters.trimTrailing(' '.characters), ''.characters);
|
||||||
|
expect(''.characters.trimTrailing('bc'.characters), ''.characters);
|
||||||
|
expect(' '.characters.trimTrailing('bc'.characters), ' '.characters);
|
||||||
|
expect(' bc'.characters.trimTrailing('bc'.characters), ' '.characters);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('TrimLeading characters', () {
|
||||||
|
expect(' ab '.characters.trimLeading(' '.characters), 'ab '.characters);
|
||||||
|
expect(' '.characters.trimLeading(' '.characters), ''.characters);
|
||||||
|
expect(' '.characters.trimLeading(' '.characters), ''.characters);
|
||||||
|
expect(' a'.characters.trimLeading(' '.characters), 'a'.characters);
|
||||||
|
expect('abc'.characters.trimLeading('ab'.characters), 'c'.characters);
|
||||||
|
expect('ababc'.characters.trimLeading('ab'.characters), 'c'.characters);
|
||||||
|
expect('abab'.characters.trimLeading('ab'.characters), ''.characters);
|
||||||
|
expect('ababcd'.characters.trimLeading('ab'.characters), 'cd'.characters);
|
||||||
|
expect(''.characters.trimLeading(''.characters), ''.characters);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Trim characters', () {
|
||||||
|
expect(' ab '.characters.trim(' '.characters), 'ab'.characters);
|
||||||
|
});
|
||||||
|
}
|
@ -35,10 +35,10 @@ void main() {
|
|||||||
tester.binding.window.physicalSizeTestValue = size;
|
tester.binding.window.physicalSizeTestValue = size;
|
||||||
tester.binding.window.devicePixelRatioTestValue = 1.0;
|
tester.binding.window.devicePixelRatioTestValue = 1.0;
|
||||||
|
|
||||||
var image = await tester.runAsync(() =>
|
var image = await tester.runAsync(() async =>
|
||||||
loadImage(FileImage(File('example/assets/Images/WeAccept/img_0.png'))));
|
loadImage(FileImage(File('example/assets/Images/WeAccept/img_0.png'))));
|
||||||
|
|
||||||
var composition = (await tester.runAsync(() =>
|
var composition = (await tester.runAsync(() async =>
|
||||||
FileLottie(File('example/assets/spinning_carrousel.zip')).load()))!;
|
FileLottie(File('example/assets/spinning_carrousel.zip')).load()))!;
|
||||||
|
|
||||||
var delegates = LottieDelegates(image: (composition, asset) {
|
var delegates = LottieDelegates(image: (composition, asset) {
|
||||||
|
BIN
test/goldens/all/Tests/ telegramalphacompat.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
test/goldens/all/Tests/anim_jpg.png
Normal file
After Width: | Height: | Size: 194 KiB |
BIN
test/goldens/all/Tests/beyondbounds.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
test/goldens/all/Tests/embeddedfont.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
test/goldens/all/Tests/framerate.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 12 KiB |
BIN
test/goldens/all/Tests/heart.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
test/goldens/all/Tests/interpolatebetweenopacitystops.png
Normal file
After Width: | Height: | Size: 107 KiB |
BIN
test/goldens/all/Tests/largecomposition.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.2 KiB |
BIN
test/goldens/all/Tests/multiline.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
test/goldens/all/Tests/opacitystops.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
test/goldens/all/Tests/precompblurdecimapprecompsize.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
test/goldens/all/Tests/roundedwithalreadyroundedcorners.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
test/goldens/all/Tests/splitpathtransform.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 7.1 KiB |
BIN
test/goldens/all/Tests/textwithpscenter.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
test/goldens/all/Tests/textwithpsleft.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
test/goldens/all/Tests/thumb.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
test/goldens/all/Tests/timestretchandstartoffset.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
test/goldens/all/Tests/wile.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
test/goldens/all/Tests/zipinlineimage.png
Normal file
After Width: | Height: | Size: 194 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 43 KiB |
@ -4,11 +4,10 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:lottie/lottie.dart';
|
import 'package:lottie/lottie.dart';
|
||||||
import 'package:lottie/src/providers/lottie_provider.dart';
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
tearDown(() {
|
tearDown(() {
|
||||||
sharedLottieCache.clear();
|
Lottie.cache.clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Should settle if no animation', (tester) async {
|
testWidgets('Should settle if no animation', (tester) async {
|
||||||
@ -324,6 +323,72 @@ void main() {
|
|||||||
expect(find.byKey(errorKey), findsNothing);
|
expect(find.byKey(errorKey), findsNothing);
|
||||||
expect(loadedCall, 1);
|
expect(loadedCall, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Cache should be synchronous', (tester) async {
|
||||||
|
var hamburgerData =
|
||||||
|
Future.value(bytesForFile('example/assets/HamburgerArrow.json'));
|
||||||
|
var mockAsset = FakeAssetBundle({
|
||||||
|
'hamburger.json': hamburgerData,
|
||||||
|
});
|
||||||
|
|
||||||
|
var loadedCall = 0;
|
||||||
|
var lottieWidget = LottieBuilder.asset(
|
||||||
|
'hamburger.json',
|
||||||
|
bundle: mockAsset,
|
||||||
|
onLoaded: (c) {
|
||||||
|
++loadedCall;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(lottieWidget);
|
||||||
|
expect(tester.widget<Lottie>(find.byType(Lottie)).composition, isNull);
|
||||||
|
await tester.pump();
|
||||||
|
expect(tester.widget<Lottie>(find.byType(Lottie)).composition, isNotNull);
|
||||||
|
|
||||||
|
await tester.pumpWidget(Column(
|
||||||
|
children: [
|
||||||
|
lottieWidget,
|
||||||
|
lottieWidget,
|
||||||
|
],
|
||||||
|
));
|
||||||
|
expect(tester.widget<Lottie>(find.byType(Lottie).at(0)).composition,
|
||||||
|
isNotNull);
|
||||||
|
expect(tester.widget<Lottie>(find.byType(Lottie).at(1)).composition,
|
||||||
|
isNotNull);
|
||||||
|
expect(loadedCall, 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Cache can be cleared', (tester) async {
|
||||||
|
var hamburgerData =
|
||||||
|
Future.value(bytesForFile('example/assets/HamburgerArrow.json'));
|
||||||
|
var mockAsset = FakeAssetBundle({
|
||||||
|
'hamburger.json': hamburgerData,
|
||||||
|
});
|
||||||
|
|
||||||
|
var loadedCall = 0;
|
||||||
|
var lottieWidget = LottieBuilder.asset(
|
||||||
|
'hamburger.json',
|
||||||
|
bundle: mockAsset,
|
||||||
|
onLoaded: (c) {
|
||||||
|
++loadedCall;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(lottieWidget);
|
||||||
|
expect(tester.widget<Lottie>(find.byType(Lottie)).composition, isNull);
|
||||||
|
await tester.pump();
|
||||||
|
expect(tester.widget<Lottie>(find.byType(Lottie)).composition, isNotNull);
|
||||||
|
|
||||||
|
Lottie.cache.clear();
|
||||||
|
|
||||||
|
await tester.pumpWidget(Center(
|
||||||
|
child: lottieWidget,
|
||||||
|
));
|
||||||
|
expect(tester.widget<Lottie>(find.byType(Lottie)).composition, isNull);
|
||||||
|
await tester.pump();
|
||||||
|
expect(tester.widget<Lottie>(find.byType(Lottie)).composition, isNotNull);
|
||||||
|
expect(loadedCall, 2);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class SynchronousFile extends Fake implements File {
|
class SynchronousFile extends Fake implements File {
|
||||||
|