mirror of
https://github.com/rive-app/rive-flutter.git
synced 2025-05-17 21:36:06 +08:00
feat: expose wrapper event class to runtime
The goal of this PR is to improve the usability of events for the Flutter runtime and to hide unnecessary editor implementation detail. This also ensures that an event is not modifiable after it has been reported (from the runtime's perspective) This is achieved by exposing runtime specific classes `RiveEvent`, `RiveOpenURLEvent` and `RiveGeneralEvent` (similar to the other runtimes), and mapping the current `Event` to these classes as an immutable object. It also maps the list of events to a Map called `properties`. This PR also: - Adds more event examples and fixes the audio example (`.stop` resulted in issues, and calling dispose, etc.) - Adds tests for events TODO: - Will need to potentially change things (and expose the `delay`) when this lands: https://github.com/rive-app/rive/pull/5951 Diffs= eae01824d feat: expose wrapper event class to runtime (#5956) Co-authored-by: Gordon <pggordonhayes@gmail.com>
This commit is contained in:
@ -1 +1 @@
|
||||
236d788ea3cf8f184a026a1b69c14af60003169c
|
||||
eae01824dd9355d8aa80503071e39067600a309b
|
||||
|
@ -0,0 +1,25 @@
|
||||
// Generated file.
|
||||
//
|
||||
// If you wish to remove Flutter's multidex support, delete this entire file.
|
||||
//
|
||||
// Modifications to this file should be done in a copy under a different name
|
||||
// as this file may be regenerated.
|
||||
|
||||
package io.flutter.app;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.multidex.MultiDex;
|
||||
|
||||
/**
|
||||
* Extension of {@link android.app.Application}, adding multidex support.
|
||||
*/
|
||||
public class FlutterMultiDexApplication extends Application {
|
||||
@Override
|
||||
@CallSuper
|
||||
protected void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
MultiDex.install(this);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.6.21'
|
||||
ext.kotlin_version = '1.9.10'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
@ -26,6 +26,6 @@ subprojects {
|
||||
project.evaluationDependsOn(':app')
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
tasks.register("clean", Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
BIN
example/assets/rating_animation.riv
Normal file
BIN
example/assets/rating_animation.riv
Normal file
Binary file not shown.
BIN
example/assets/url_event_button.riv
Normal file
BIN
example/assets/url_event_button.riv
Normal file
Binary file not shown.
@ -1,20 +1,39 @@
|
||||
PODS:
|
||||
- audio_session (0.0.1):
|
||||
- Flutter
|
||||
- Flutter (1.0.0)
|
||||
- just_audio (0.0.1):
|
||||
- Flutter
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- rive_common (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- audio_session (from `.symlinks/plugins/audio_session/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- just_audio (from `.symlinks/plugins/just_audio/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- rive_common (from `.symlinks/plugins/rive_common/ios`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
audio_session:
|
||||
:path: ".symlinks/plugins/audio_session/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
just_audio:
|
||||
:path: ".symlinks/plugins/just_audio/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
rive_common:
|
||||
:path: ".symlinks/plugins/rive_common/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
audio_session: 4f3e461722055d21515cf3261b64c973c062f345
|
||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||
just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa
|
||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||
rive_common: 8a159d68033a8b073e5853acc50f03aa486a2888
|
||||
|
||||
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
|
||||
|
70
example/lib/event_open_url_button.dart
Normal file
70
example/lib/event_open_url_button.dart
Normal file
@ -0,0 +1,70 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rive/rive.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
/// This example demonstrates how to open a URL from a Rive [RiveOpenUrlEvent]..
|
||||
class EventOpenUrlButton extends StatefulWidget {
|
||||
const EventOpenUrlButton({super.key});
|
||||
|
||||
@override
|
||||
State<EventOpenUrlButton> createState() => _EventOpenUrlButtonState();
|
||||
}
|
||||
|
||||
class _EventOpenUrlButtonState extends State<EventOpenUrlButton> {
|
||||
late StateMachineController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void onInit(Artboard artboard) async {
|
||||
_controller = StateMachineController.fromArtboard(artboard, 'button')!;
|
||||
artboard.addController(_controller);
|
||||
|
||||
_controller.addEventListener(onRiveEvent);
|
||||
}
|
||||
|
||||
void onRiveEvent(RiveEvent event) {
|
||||
if (event is RiveOpenURLEvent) {
|
||||
try {
|
||||
final Uri url = Uri.parse(event.url);
|
||||
launchUrl(url);
|
||||
} on Exception catch (e) {
|
||||
debugPrint(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.removeEventListener(onRiveEvent);
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Event Open URL'),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: RiveAnimation.asset(
|
||||
'assets/url_event_button.riv',
|
||||
onInit: onInit,
|
||||
),
|
||||
),
|
||||
const Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Text('Open URL: https://rive.app'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -13,18 +13,41 @@ class EventSounds extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _EventSoundsState extends State<EventSounds> {
|
||||
final _audioPlayer = AudioPlayer();
|
||||
late final StateMachineController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_audioPlayer.setAsset('assets/step.mp3');
|
||||
}
|
||||
|
||||
Future<void> _onRiveInit(Artboard artboard) async {
|
||||
final audioPlayer = AudioPlayer();
|
||||
await audioPlayer!.setAsset('assets/step.mp3');
|
||||
final controller =
|
||||
StateMachineController.fromArtboard(artboard, 'skill-controller');
|
||||
artboard.addController(controller!);
|
||||
controller.addEventListener((event) {
|
||||
if (event.name == 'Step') {
|
||||
audioPlayer.stop();
|
||||
audioPlayer.play();
|
||||
}
|
||||
});
|
||||
_controller =
|
||||
StateMachineController.fromArtboard(artboard, 'skill-controller')!;
|
||||
artboard.addController(_controller);
|
||||
_controller.addEventListener(onRiveEvent);
|
||||
}
|
||||
|
||||
void onRiveEvent(RiveEvent event) {
|
||||
// Seconds since the event was triggered and it being reported.
|
||||
// This can be used to scrub the audio forward to the precise locaiton
|
||||
// if needed.
|
||||
// ignore: unused_local_variable
|
||||
var seconds = event.secondsDelay;
|
||||
|
||||
if (event.name == 'Step') {
|
||||
_audioPlayer.seek(Duration.zero);
|
||||
_audioPlayer.play();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.removeEventListener(onRiveEvent);
|
||||
_controller.dispose();
|
||||
_audioPlayer.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
|
75
example/lib/event_star_rating.dart
Normal file
75
example/lib/event_star_rating.dart
Normal file
@ -0,0 +1,75 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rive/rive.dart';
|
||||
|
||||
/// This example demonstrates how to retrieve custom properties set on a Rive
|
||||
/// event, and update the UI accordingly.
|
||||
class EventStarRating extends StatefulWidget {
|
||||
const EventStarRating({super.key});
|
||||
|
||||
@override
|
||||
State<EventStarRating> createState() => _EventStarRatingState();
|
||||
}
|
||||
|
||||
class _EventStarRatingState extends State<EventStarRating> {
|
||||
late StateMachineController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
String ratingValue = 'Rating: 0';
|
||||
|
||||
void onInit(Artboard artboard) async {
|
||||
_controller =
|
||||
StateMachineController.fromArtboard(artboard, 'State Machine 1')!;
|
||||
artboard.addController(_controller);
|
||||
|
||||
_controller.addEventListener(onRiveEvent);
|
||||
}
|
||||
|
||||
void onRiveEvent(RiveEvent event) {
|
||||
// Access custom properties defined on the event
|
||||
var rating = event.properties['rating'] as double;
|
||||
// Schedule the setState for the next frame, as an event can be
|
||||
// triggered during a current frame update
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
setState(() {
|
||||
ratingValue = 'Rating: $rating';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.removeEventListener(onRiveEvent);
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Event Star Rating'),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: RiveAnimation.asset(
|
||||
'assets/rating_animation.riv',
|
||||
onInit: onInit,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
ratingValue,
|
||||
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.w600),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -4,7 +4,9 @@ import 'package:rive_example/custom_asset_loading.dart';
|
||||
import 'package:rive_example/custom_cached_asset_loading.dart';
|
||||
import 'package:rive_example/carousel.dart';
|
||||
import 'package:rive_example/custom_controller.dart';
|
||||
import 'package:rive_example/event_open_url_button.dart';
|
||||
import 'package:rive_example/event_sounds.dart';
|
||||
import 'package:rive_example/event_star_rating.dart';
|
||||
import 'package:rive_example/example_state_machine.dart';
|
||||
import 'package:rive_example/liquid_download.dart';
|
||||
import 'package:rive_example/little_machine.dart';
|
||||
@ -59,7 +61,9 @@ class _RiveExampleAppState extends State<RiveExampleApp> {
|
||||
const _Page('Basic Text', BasicText()),
|
||||
const _Page('Custom Asset Loading', CustomAssetLoading()),
|
||||
const _Page('Custom Cached Asset Loading', CustomCachedAssetLoading()),
|
||||
const _Page('Event Open URL Button', EventOpenUrlButton()),
|
||||
const _Page('Event Sounds', EventSounds()),
|
||||
const _Page('Event Star Rating', EventStarRating()),
|
||||
];
|
||||
|
||||
@override
|
||||
|
@ -9,6 +9,8 @@ PODS:
|
||||
- FlutterMacOS
|
||||
- rive_common (0.0.1):
|
||||
- FlutterMacOS
|
||||
- url_launcher_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`)
|
||||
@ -16,6 +18,7 @@ DEPENDENCIES:
|
||||
- just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/macos`)
|
||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- rive_common (from `Flutter/ephemeral/.symlinks/plugins/rive_common/macos`)
|
||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
audio_session:
|
||||
@ -28,6 +31,8 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
||||
rive_common:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/rive_common/macos
|
||||
url_launcher_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72
|
||||
@ -35,7 +40,8 @@ SPEC CHECKSUMS:
|
||||
just_audio: 9b67ca7b97c61cfc9784ea23cd8cc55eb226d489
|
||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||
rive_common: acedcab7802c0ece4b0d838b71d7deb637e1309a
|
||||
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
|
||||
|
||||
PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7
|
||||
|
||||
COCOAPODS: 1.12.1
|
||||
COCOAPODS: 1.11.3
|
||||
|
@ -9,12 +9,13 @@ environment:
|
||||
sdk: '>=2.17.0 <3.0.0'
|
||||
|
||||
dependencies:
|
||||
just_audio: ^0.9.34
|
||||
flutter:
|
||||
sdk: flutter
|
||||
rive:
|
||||
path: ../
|
||||
http:
|
||||
just_audio: ^0.9.34
|
||||
url_launcher: ^6.1.14
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -15,6 +15,7 @@ export 'package:rive/src/rive_core/artboard.dart';
|
||||
export 'package:rive/src/rive_core/assets/font_asset.dart';
|
||||
export 'package:rive/src/rive_core/assets/image_asset.dart';
|
||||
export 'package:rive/src/rive_core/nested_artboard.dart';
|
||||
export 'package:rive/src/rive_core/open_url_target.dart';
|
||||
export 'package:rive/src/rive_core/rive_animation_controller.dart';
|
||||
export 'package:rive/src/rive_core/runtime/exceptions/rive_format_error_exception.dart';
|
||||
export 'package:rive/src/rive_core/runtime/runtime_header.dart'
|
||||
@ -29,4 +30,5 @@ export 'package:rive/src/rive_core/text/text_value_run.dart';
|
||||
export 'package:rive/src/rive_file.dart';
|
||||
export 'package:rive/src/rive_scene.dart';
|
||||
export 'package:rive/src/runtime_artboard.dart';
|
||||
export 'package:rive/src/runtime_event.dart';
|
||||
export 'package:rive/src/widgets/rive_animation.dart';
|
||||
|
@ -11,6 +11,9 @@ export 'package:rive/src/generated/event_base.dart';
|
||||
class Event extends EventBase {
|
||||
final List<CustomProperty> customProperties = [];
|
||||
|
||||
double _secondsDelay = 0.0;
|
||||
double get secondsDelay => _secondsDelay;
|
||||
|
||||
@override
|
||||
void update(int dirt) {}
|
||||
|
||||
@ -47,6 +50,7 @@ class Event extends EventBase {
|
||||
void trigger(CallbackData data) {
|
||||
if (data.context is StateMachineController) {
|
||||
var controller = data.context as StateMachineController;
|
||||
_secondsDelay = data.delay;
|
||||
controller.reportEvent(this);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
import 'package:rive/src/generated/open_url_event_base.dart';
|
||||
import 'package:rive/src/rive_core/artboard.dart';
|
||||
import 'package:rive/src/rive_core/open_url_target.dart';
|
||||
|
||||
export 'package:rive/src/generated/open_url_event_base.dart';
|
||||
|
||||
enum OpenUrlTarget { blank, parent, self, top }
|
||||
|
||||
class OpenUrlEvent extends OpenUrlEventBase {
|
||||
@override
|
||||
void update(int dirt) {}
|
||||
|
2
lib/src/rive_core/open_url_target.dart
Normal file
2
lib/src/rive_core/open_url_target.dart
Normal file
@ -0,0 +1,2 @@
|
||||
/// Open URL event target types.
|
||||
enum OpenUrlTarget { blank, parent, self, top }
|
@ -27,6 +27,7 @@ import 'package:rive/src/rive_core/nested_artboard.dart';
|
||||
import 'package:rive/src/rive_core/node.dart';
|
||||
import 'package:rive/src/rive_core/rive_animation_controller.dart';
|
||||
import 'package:rive/src/rive_core/shapes/shape.dart';
|
||||
import 'package:rive/src/runtime_event.dart';
|
||||
import 'package:rive_common/math.dart';
|
||||
|
||||
/// Callback signature for state machine state changes
|
||||
@ -37,7 +38,7 @@ typedef OnStateChange = void Function(
|
||||
typedef OnLayerStateChange = void Function(LayerState);
|
||||
|
||||
/// Callback signature for events firing.
|
||||
typedef OnEvent = void Function(Event);
|
||||
typedef OnEvent = void Function(RiveEvent);
|
||||
|
||||
class LayerController {
|
||||
final StateMachineLayer layer;
|
||||
@ -281,7 +282,12 @@ class StateMachineController extends RiveAnimationController<CoreContext>
|
||||
@Deprecated('Use `addEventListener` instead.') this.onStateChange,
|
||||
});
|
||||
|
||||
/// Adds a Rive event listener to this controller.
|
||||
///
|
||||
/// Documentation: https://help.rive.app/runtimes/rive-events
|
||||
void addEventListener(OnEvent callback) => _eventListeners.add(callback);
|
||||
|
||||
/// Removes listener from this controller.
|
||||
void removeEventListener(OnEvent callback) =>
|
||||
_eventListeners.remove(callback);
|
||||
|
||||
@ -387,6 +393,7 @@ class StateMachineController extends RiveAnimationController<CoreContext>
|
||||
@override
|
||||
void dispose() {
|
||||
_clearLayerControllers();
|
||||
_eventListeners.clear();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -420,7 +427,12 @@ class StateMachineController extends RiveAnimationController<CoreContext>
|
||||
if (_firedEvents.isNotEmpty) {
|
||||
var events = _firedEvents.toList(growable: false);
|
||||
_firedEvents.clear();
|
||||
_eventListeners.toList().forEach(events.forEach);
|
||||
|
||||
_eventListeners.toList().forEach((listener) {
|
||||
for (final event in events) {
|
||||
listener(RiveEvent.fromCoreEvent(event));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
105
lib/src/runtime_event.dart
Normal file
105
lib/src/runtime_event.dart
Normal file
@ -0,0 +1,105 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:rive/src/rive_core/custom_property_boolean.dart';
|
||||
import 'package:rive/src/rive_core/custom_property_number.dart';
|
||||
import 'package:rive/src/rive_core/custom_property_string.dart';
|
||||
import 'package:rive/src/rive_core/event.dart';
|
||||
import 'package:rive/src/rive_core/open_url_event.dart';
|
||||
import 'package:rive/src/rive_core/open_url_target.dart';
|
||||
|
||||
/// A Rive Event that is reported from an StateMachineController.
|
||||
///
|
||||
/// See:
|
||||
/// - [RiveGeneralEvent]
|
||||
/// - [RiveOpenURLEvent]
|
||||
///
|
||||
/// For specific event types.
|
||||
///
|
||||
/// Documentation: https://help.rive.app/runtimes/rive-events
|
||||
@immutable
|
||||
class RiveEvent {
|
||||
final String name;
|
||||
final double secondsDelay;
|
||||
final Map<String, dynamic> properties;
|
||||
|
||||
const RiveEvent({
|
||||
required this.name,
|
||||
required this.secondsDelay,
|
||||
required this.properties,
|
||||
});
|
||||
|
||||
factory RiveEvent.fromCoreEvent(Event event) {
|
||||
final Map<String, dynamic> properties = {};
|
||||
for (final property in event.customProperties) {
|
||||
dynamic value;
|
||||
switch (property.coreType) {
|
||||
case CustomPropertyNumberBase.typeKey:
|
||||
value = (property as CustomPropertyNumber).propertyValue;
|
||||
break;
|
||||
case CustomPropertyStringBase.typeKey:
|
||||
value = (property as CustomPropertyString).propertyValue;
|
||||
break;
|
||||
case CustomPropertyBooleanBase.typeKey:
|
||||
value = (property as CustomPropertyBoolean).propertyValue;
|
||||
break;
|
||||
}
|
||||
if (value != null) {
|
||||
properties[property.name] = value;
|
||||
}
|
||||
}
|
||||
if (event.coreType == OpenUrlEventBase.typeKey) {
|
||||
event = event as OpenUrlEvent;
|
||||
return RiveOpenURLEvent(
|
||||
name: event.name,
|
||||
url: event.url,
|
||||
target: event.target,
|
||||
secondsDelay: event.secondsDelay,
|
||||
properties: properties,
|
||||
);
|
||||
} else {
|
||||
return RiveGeneralEvent(
|
||||
name: event.name,
|
||||
secondsDelay: event.secondsDelay,
|
||||
properties: properties,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => 'Rive Event - name: $name, properties: $properties';
|
||||
}
|
||||
|
||||
/// A general Rive event that provides information about the event.
|
||||
@immutable
|
||||
class RiveGeneralEvent extends RiveEvent {
|
||||
const RiveGeneralEvent({
|
||||
required String name,
|
||||
required double secondsDelay,
|
||||
required Map<String, dynamic> properties,
|
||||
}) : super(name: name, secondsDelay: secondsDelay, properties: properties);
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'Rive GeneralEvent - name: $name, properties: $properties';
|
||||
}
|
||||
|
||||
/// An Open URL Rive event that provides information about the URL and target.
|
||||
///
|
||||
/// See:
|
||||
/// - [url]
|
||||
/// - [target]
|
||||
@immutable
|
||||
class RiveOpenURLEvent extends RiveEvent {
|
||||
final String url;
|
||||
final OpenUrlTarget target;
|
||||
const RiveOpenURLEvent({
|
||||
required String name,
|
||||
required double secondsDelay,
|
||||
required Map<String, dynamic> properties,
|
||||
required this.target,
|
||||
required this.url,
|
||||
}) : super(name: name, secondsDelay: secondsDelay, properties: properties);
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'Rive OpenURLEvent - name: $name, properties: $properties';
|
||||
}
|
3
test/assets/events_from_trigger_test.riv
Normal file
3
test/assets/events_from_trigger_test.riv
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:43496fca427b3da9640dbb646fe20a6982fdb14586ffd777ccd2f5395aa8b78a
|
||||
size 415
|
Reference in New Issue
Block a user