diff --git a/example/.metadata b/example/.metadata index 9817e35..b5c370f 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,42 @@ # This file should be version controlled and should not be manually edited. version: - revision: ee032f67c734e607d8ea5c870ba744daf4bf56e7 - channel: master + revision: "41456452f29d64e8deb623a3c927524bcf9f111b" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + - platform: android + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + - platform: ios + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + - platform: linux + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + - platform: macos + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + - platform: web + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + - platform: windows + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/example/assets/particle_image.png b/example/assets/particle_image.png new file mode 100644 index 0000000..838b361 Binary files /dev/null and b/example/assets/particle_image.png differ diff --git a/example/pubspec.lock b/example/pubspec.lock index 49535ea..9a652ad 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,44 +5,42 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" + version: "1.3.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.19.0" confetti: dependency: "direct main" description: @@ -54,16 +52,18 @@ packages: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + url: "https://pub.dev" source: hosted - version: "0.1.2" + version: "1.0.6" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.3.1" flutter: dependency: "direct main" description: flutter @@ -74,88 +74,131 @@ packages: description: flutter source: sdk version: "0.0.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + url: "https://pub.dev" + source: hosted + version: "10.0.7" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + url: "https://pub.dev" + source: hosted + version: "3.0.8" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" source: hosted - version: "0.1.4" + version: "0.11.1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.15.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" source: hosted - version: "1.8.1" + version: "1.9.0" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.3.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + url: "https://pub.dev" source: hosted - version: "0.4.9" + version: "0.7.3" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + url: "https://pub.dev" + source: hosted + version: "14.3.0" sdks: - dart: ">=2.17.0 <3.0.0" - flutter: ">=3.0.0" + dart: ">=3.4.0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 5272a54..57e4d1a 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -11,7 +11,7 @@ environment: dependencies: confetti: path: ../ - cupertino_icons: ^0.1.2 + cupertino_icons: ^1.0.6 flutter: sdk: flutter @@ -20,4 +20,7 @@ dev_dependencies: sdk: flutter flutter: - uses-material-design: true \ No newline at end of file + uses-material-design: true + + assets: + - assets/particle_image.png diff --git a/lib/src/confetti.dart b/lib/src/confetti.dart index 1014da7..1e7a4b3 100644 --- a/lib/src/confetti.dart +++ b/lib/src/confetti.dart @@ -1,4 +1,5 @@ import 'dart:math'; +import 'dart:ui' as ui; import 'package:confetti/src/particle.dart'; import 'package:flutter/material.dart'; @@ -28,6 +29,7 @@ class ConfettiWidget extends StatefulWidget { this.canvas, this.child, this.createParticlePath, + this.imagePath, }) : assert( emissionFrequency >= 0 && emissionFrequency <= 1 && @@ -135,6 +137,9 @@ class ConfettiWidget extends StatefulWidget { /// Child widget to display final Widget? child; + /// image path to display + final String? imagePath; + @override _ConfettiWidgetState createState() => _ConfettiWidgetState(); } @@ -171,11 +176,22 @@ class _ConfettiWidgetState extends State minimumSize: widget.minimumSize, maximumSize: widget.maximumSize, particleDrag: widget.particleDrag, - createParticlePath: widget.createParticlePath); - - _particleSystem.addListener(_particleSystemListener); + createParticlePath: widget.createParticlePath, + ); _initAnimation(); + + // with image + if (widget.imagePath != null) { + _loadParticleImage(widget.imagePath!); + } else { + _particleSystem.addListener(_particleSystemListener); + } + } + + Future _loadParticleImage(String imagePath) async { + await _particleSystem.loadImage(imagePath); + _particleSystem.addListener(_particleSystemListener); } void _initAnimation() { @@ -305,6 +321,7 @@ class _ConfettiWidgetState extends State strokeColor: widget.strokeColor, particles: _particleSystem.particles, paintEmitterTarget: widget.displayTarget, + withImage: widget.imagePath != null, ), child: widget.child, ), @@ -325,6 +342,7 @@ class ParticlePainter extends CustomPainter { ParticlePainter( Listenable? repaint, { required this.particles, + required this.withImage, bool paintEmitterTarget = true, Color emitterTargetColor = Colors.black, Color strokeColor = Colors.black, @@ -350,13 +368,19 @@ class ParticlePainter extends CustomPainter { final Paint _particlePaint; final Paint _particleStrokePaint; final double strokeWidth; + final bool withImage; @override void paint(Canvas canvas, Size size) { if (_paintEmitterTarget) { _paintEmitter(canvas); } - _paintParticles(canvas); + + if (withImage) { + _paintParticlesWithImage(canvas); + } else { + _paintParticles(canvas); + } } // TODO: seperate this @@ -387,6 +411,31 @@ class ParticlePainter extends CustomPainter { } } + void _paintParticlesWithImage(Canvas canvas) { + for (final particle in particles) { + final rotationMatrix4 = Matrix4.identity() + ..translate(particle.location.dx, particle.location.dy) + ..rotateX(particle.angleX) + ..rotateY(particle.angleY) + ..rotateZ(particle.angleZ); + + final finalPath = particle.path.transform(rotationMatrix4.storage); + final particlePath = particle.path; + + canvas.save(); + canvas.translate(particle.location.dx, particle.location.dy); + canvas.clipPath(particlePath); + + final image = particle.image; + canvas.drawImage(image!, Offset(-particle.size.width / 2, -particle.size.width / 2), _particlePaint); + + if (strokeWidth > 0) { + canvas.drawPath(particlePath, _particleStrokePaint); + } + canvas.restore(); + } + } + @override bool shouldRepaint(CustomPainter oldDelegate) { return true; diff --git a/lib/src/particle.dart b/lib/src/particle.dart index da781b0..b0ca13b 100644 --- a/lib/src/particle.dart +++ b/lib/src/particle.dart @@ -1,12 +1,15 @@ import 'dart:math'; import 'dart:ui'; +import 'dart:async'; import 'package:flutter/material.dart'; import 'package:vector_math/vector_math.dart' as vmath; import 'package:confetti/src/helper.dart'; - +import 'package:flutter/services.dart' show rootBundle; import 'enums/blast_directionality.dart'; +import 'dart:typed_data'; +import 'dart:ui' as ui; enum ParticleSystemStatus { started, @@ -82,6 +85,7 @@ class ParticleSystem extends ChangeNotifier { late double _bottomBorder; late double _rightBorder; late double _leftBorder; + ui.Image? _image = null; final Random _rand; @@ -166,8 +170,29 @@ class ParticleSystem extends ChangeNotifier { List _generateParticles({int number = 1}) { return List.generate( number, - (i) => Particle(_generateParticleForce(), _randomColor(), _randomSize(), - _gravity, _particleDrag, _createParticlePath)); + (i) => Particle( + _generateParticleForce(), _randomColor(), _randomSize(), + _gravity, _particleDrag, _createParticlePath, + _image, + ), + ); + } + + // 画像をロードする関数 + // 非同期的に画像を読み込むメソッド + Future loadImage(String path) async { + try { + final ByteData data = await rootBundle.load(path); + final Uint8List bytes = data.buffer.asUint8List(); + final Completer completer = Completer(); + ui.decodeImageFromList(bytes, (ui.Image img) { + completer.complete(img); + }); + _image = await completer.future; + } catch (e) { + print('Error loading image: $e'); + _image = null; + } } double get _randomBlastDirection => @@ -204,8 +229,11 @@ class ParticleSystem extends ChangeNotifier { } class Particle { - Particle(vmath.Vector2 startUpForce, Color color, Size size, double gravity, - double particleDrag, Path Function(Size size)? createParticlePath) + Particle( + vmath.Vector2 startUpForce, Color color, Size size, double gravity, + double particleDrag, Path Function(Size size)? createParticlePath, + ui.Image? image, + ) : _startUpForce = startUpForce, _color = color, _mass = Helper.randomize(1, 11), @@ -214,14 +242,18 @@ class Particle { _acceleration = vmath.Vector2.zero(), _velocity = vmath.Vector2(Helper.randomize(-3, 3), Helper.randomize(-3, 3)), - // _size = size, + _size = size, _pathShape = createParticlePath != null ? createParticlePath(size) : createPath(size), _aVelocityX = Helper.randomize(-0.1, 0.1), _aVelocityY = Helper.randomize(-0.1, 0.1), _aVelocityZ = Helper.randomize(-0.1, 0.1), - _gravity = lerpDouble(0.1, 5, gravity); + _gravity = lerpDouble(0.1, 5, gravity), + _image = image; + + ui.Image? _image; + final Size _size; final vmath.Vector2 _startUpForce; @@ -311,6 +343,9 @@ class Particle { return Offset(_location.x, _location.y); } + ui.Image? get image => _image; + Size get size => _size; + Color get color => _color; Path get path => _pathShape; diff --git a/pubspec.lock b/pubspec.lock index b732620..cf00db9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,51 +5,50 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" + version: "1.3.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.19.0" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.3.1" flutter: dependency: "direct main" description: flutter @@ -59,7 +58,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 + url: "https://pub.dev" source: hosted version: "1.0.4" flutter_test: @@ -67,95 +67,139 @@ packages: description: flutter source: sdk version: "0.0.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + url: "https://pub.dev" + source: hosted + version: "10.0.7" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + url: "https://pub.dev" + source: hosted + version: "3.0.8" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c + url: "https://pub.dev" source: hosted version: "1.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" source: hosted - version: "0.1.4" + version: "0.11.1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.15.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" source: hosted - version: "1.8.1" + version: "1.9.0" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.3.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + url: "https://pub.dev" source: hosted - version: "0.4.9" + version: "0.7.3" vector_math: dependency: "direct main" description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + url: "https://pub.dev" + source: hosted + version: "14.3.0" sdks: - dart: ">=2.17.0 <3.0.0" - flutter: ">=3.0.0" + dart: ">=3.4.0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54"