diff --git a/.rive_head b/.rive_head index cf90ed1..2716648 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -0b1834a1ac1df3392314f44a3d7dfb135a8a3f6b +fa7c55934e1523fd1de55dcc1540d9c19934cdc0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 12fbb46..8e06363 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ +## 0.13.5 +- Migrates to `dart:js_interop` and `package:web` APIs. +- DEPRECATED: `RiveFile.initializeText` - use `RiveFile.initialize` instead. This now initializes the Rive audio, text, and layout engine. Call `await RiveFile.initialize()` before doing `RiveFile.import`. `RiveFile.asset`, `RiveFile.network`, and `RiveFile.file` will call initialize automatically if it has not been initialized. Alternatively, you can also call `unawaited(RiveFile.initialize());` in the `main` method on app start to make the first graphic load faster. + ## 0.13.4 + - Fixed an issue with [TickerMode](https://api.flutter.dev/flutter/widgets/TickerMode-class.html) value not pausing a Rive graphic. Thanks to 'jaggernod' for the [contribution](https://github.com/rive-app/rive-flutter/pull/380). - Bump rive_common to pick up the Privacy manifest for iOS & macOS runtimes diff --git a/example/lib/example_state_machine.dart b/example/lib/example_state_machine.dart index a1eda41..cec4565 100644 --- a/example/lib/example_state_machine.dart +++ b/example/lib/example_state_machine.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:rive/rive.dart'; /// An example showing how to drive two boolean state machine inputs. @@ -11,11 +10,7 @@ class ExampleStateMachine extends StatefulWidget { } class _ExampleStateMachineState extends State { - /// Tracks if the animation is playing by whether controller is running. - bool get isPlaying => _controller?.isActive ?? false; - Artboard? _riveArtboard; - StateMachineController? _controller; SMIBool? _hoverInput; SMIBool? _pressInput; @@ -23,26 +18,23 @@ class _ExampleStateMachineState extends State { void initState() { super.initState(); - // Load the animation file from the bundle, note that you could also - // download this. The RiveFile just expects a list of bytes. - rootBundle.load('assets/rocket.riv').then( - (data) async { - // Load the RiveFile from the binary data. - final file = RiveFile.import(data); + _loadRiveFile(); + } - // The artboard is the root of the animation and gets drawn in the - // Rive widget. - final artboard = file.mainArtboard; - var controller = - StateMachineController.fromArtboard(artboard, 'Button'); - if (controller != null) { - artboard.addController(controller); - _hoverInput = controller.getBoolInput('Hover'); - _pressInput = controller.getBoolInput('Press'); - } - setState(() => _riveArtboard = artboard); - }, - ); + Future _loadRiveFile() async { + // Load the animation file from the bundle. + final riveFile = await RiveFile.asset('assets/rocket.riv'); + + // The artboard is the root of the animation and gets drawn in the + // Rive widget. + final artboard = riveFile.mainArtboard; + var controller = StateMachineController.fromArtboard(artboard, 'Button'); + if (controller != null) { + artboard.addController(controller); + _hoverInput = controller.getBoolInput('Hover'); + _pressInput = controller.getBoolInput('Press'); + } + setState(() => _riveArtboard = artboard); } @override diff --git a/example/lib/liquid_download.dart b/example/lib/liquid_download.dart index 5ec3c3c..e34956f 100644 --- a/example/lib/liquid_download.dart +++ b/example/lib/liquid_download.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:rive/rive.dart'; /// An example showing how to drive a StateMachine via a trigger and number @@ -12,38 +11,28 @@ class LiquidDownload extends StatefulWidget { } class _LiquidDownloadState extends State { - /// Tracks if the animation is playing by whether controller is running. - bool get isPlaying => _controller?.isActive ?? false; - Artboard? _riveArtboard; - StateMachineController? _controller; SMITrigger? _start; SMINumber? _progress; @override void initState() { super.initState(); + _loadRiveFile(); + } - // Load the animation file from the bundle, note that you could also - // download this. The RiveFile just expects a list of bytes. - rootBundle.load('assets/liquid_download.riv').then( - (data) async { - // Load the RiveFile from the binary data. - final file = RiveFile.import(data); - - // The artboard is the root of the animation and gets drawn in the - // Rive widget. - final artboard = file.mainArtboard; - var controller = - StateMachineController.fromArtboard(artboard, 'Download'); - if (controller != null) { - artboard.addController(controller); - _start = controller.getTriggerInput('Download'); - _progress = controller.getNumberInput('Progress'); - } - setState(() => _riveArtboard = artboard); - }, - ); + Future _loadRiveFile() async { + final file = await RiveFile.asset('assets/liquid_download.riv'); + // The artboard is the root of the animation and gets drawn in the + // Rive widget. + final artboard = file.mainArtboard; + var controller = StateMachineController.fromArtboard(artboard, 'Download'); + if (controller != null) { + artboard.addController(controller); + _start = controller.getTriggerInput('Download'); + _progress = controller.getNumberInput('Progress'); + } + setState(() => _riveArtboard = artboard); } @override diff --git a/example/lib/little_machine.dart b/example/lib/little_machine.dart index 5c857b6..35caa0a 100644 --- a/example/lib/little_machine.dart +++ b/example/lib/little_machine.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:rive/rive.dart'; /// An example showing how to drive a StateMachine via a trigger input. @@ -11,42 +10,34 @@ class LittleMachine extends StatefulWidget { } class _LittleMachineState extends State { - /// Tracks if the animation is playing by whether controller is running. - bool get isPlaying => _controller?.isActive ?? false; - /// Message that displays when state has changed String stateChangeMessage = ''; Artboard? _riveArtboard; - StateMachineController? _controller; SMITrigger? _trigger; @override void initState() { super.initState(); + _loadRiveFile(); + } - // Load the animation file from the bundle, note that you could also - // download this. The RiveFile just expects a list of bytes. - rootBundle.load('assets/little_machine.riv').then( - (data) async { - // Load the RiveFile from the binary data. - final file = RiveFile.import(data); + Future _loadRiveFile() async { + final file = await RiveFile.asset('assets/little_machine.riv'); - // The artboard is the root of the animation and gets drawn in the - // Rive widget. - final artboard = file.mainArtboard; - var controller = StateMachineController.fromArtboard( - artboard, - 'State Machine 1', - onStateChange: _onStateChange, - ); - if (controller != null) { - artboard.addController(controller); - _trigger = controller.getTriggerInput('Trigger 1'); - } - setState(() => _riveArtboard = artboard); - }, + // The artboard is the root of the animation and gets drawn in the + // Rive widget. + final artboard = file.mainArtboard; + var controller = StateMachineController.fromArtboard( + artboard, + 'State Machine 1', + onStateChange: _onStateChange, ); + if (controller != null) { + artboard.addController(controller); + _trigger = controller.getTriggerInput('Trigger 1'); + } + setState(() => _riveArtboard = artboard); } /// Do something when the state machine changes state diff --git a/example/lib/main.dart b/example/lib/main.dart index c829356..1c26531 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,4 +1,7 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; +import 'package:rive/rive.dart'; import 'package:rive_example/custom_asset_loading.dart'; import 'package:rive_example/custom_cached_asset_loading.dart'; @@ -22,19 +25,27 @@ import 'package:rive_example/skinning_demo.dart'; import 'package:rive_example/state_machine_skills.dart'; import 'package:rive_example/basic_text.dart'; -void main() => runApp( - MaterialApp( - title: 'Rive Example', - home: const RiveExampleApp(), - darkTheme: ThemeData.dark().copyWith( - scaffoldBackgroundColor: _backgroundColor, - appBarTheme: const AppBarTheme(backgroundColor: _appBarColor), - colorScheme: - ColorScheme.fromSwatch().copyWith(primary: _primaryColor), - ), - themeMode: ThemeMode.dark, +void main() { + /// Initialize Rive's text, audio, and layout engines. + /// This will automatically be called the first time a RiveFile is loaded if + /// it has not been initialized. And does not need to be called. + /// + /// However, calling it early here makes the first + /// visible Rive graphic load faster. + unawaited(RiveFile.initialize()); + runApp( + MaterialApp( + title: 'Rive Example', + home: const RiveExampleApp(), + darkTheme: ThemeData.dark().copyWith( + scaffoldBackgroundColor: _backgroundColor, + appBarTheme: const AppBarTheme(backgroundColor: _appBarColor), + colorScheme: ColorScheme.fromSwatch().copyWith(primary: _primaryColor), ), - ); + themeMode: ThemeMode.dark, + ), + ); +} /// An example application demoing Rive. class RiveExampleApp extends StatefulWidget { diff --git a/example/lib/state_machine_skills.dart b/example/lib/state_machine_skills.dart index e815c3a..dccf144 100644 --- a/example/lib/state_machine_skills.dart +++ b/example/lib/state_machine_skills.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:rive/rive.dart'; /// An example showing how to drive a StateMachine via one numeric input. @@ -11,36 +10,29 @@ class StateMachineSkills extends StatefulWidget { } class _StateMachineSkillsState extends State { - /// Tracks if the animation is playing by whether controller is running. - bool get isPlaying => _controller?.isActive ?? false; - Artboard? _riveArtboard; - StateMachineController? _controller; SMINumber? _levelInput; @override void initState() { super.initState(); - // Load the animation file from the bundle, note that you could also - // download this. The RiveFile just expects a list of bytes. - rootBundle.load('assets/skills.riv').then( - (data) async { - // Load the RiveFile from the binary data. - final file = RiveFile.import(data); + _loadRiveFile(); + } - // The artboard is the root of the animation and gets drawn in the - // Rive widget. - final artboard = file.mainArtboard; - var controller = - StateMachineController.fromArtboard(artboard, 'Designer\'s Test'); - if (controller != null) { - artboard.addController(controller); - _levelInput = controller.getNumberInput('Level'); - } - setState(() => _riveArtboard = artboard); - }, - ); + Future _loadRiveFile() async { + final file = await RiveFile.asset('assets/skills.riv'); + + // The artboard is the root of the animation and gets drawn in the + // Rive widget. + final artboard = file.mainArtboard; + var controller = + StateMachineController.fromArtboard(artboard, 'Designer\'s Test'); + if (controller != null) { + artboard.addController(controller); + _levelInput = controller.getNumberInput('Level'); + } + setState(() => _riveArtboard = artboard); } @override diff --git a/lib/src/rive_core/nested_artboard.dart b/lib/src/rive_core/nested_artboard.dart index 6b475ed..543246b 100644 --- a/lib/src/rive_core/nested_artboard.dart +++ b/lib/src/rive_core/nested_artboard.dart @@ -16,6 +16,7 @@ import 'package:rive_common/math.dart'; export 'package:rive/src/generated/nested_artboard_base.dart'; enum NestedArtboardFitType { + // ignore: lines_longer_than_80_chars fill, // Default value - scales to fill available view without maintaining aspect ratio contain, cover, diff --git a/lib/src/rive_file.dart b/lib/src/rive_file.dart index b4cb43e..f1643e0 100644 --- a/lib/src/rive_file.dart +++ b/lib/src/rive_file.dart @@ -38,7 +38,6 @@ import 'package:rive/src/rive_core/runtime/exceptions/rive_format_error_exceptio import 'package:rive/src/rive_core/runtime/runtime_header.dart'; import 'package:rive/src/runtime_nested_artboard.dart'; import 'package:rive_common/rive_text.dart'; - import 'package:rive_common/utilities.dart'; typedef Core? ObjectGenerator(int coreTypeKey); @@ -137,6 +136,7 @@ class RiveFile { return propertyToField; } + @Deprecated('This method will always return true and is no longer accurate') // Peek into the bytes to see if we're going to need to use the text runtime. static bool needsTextRuntime(ByteData bytes) { var reader = BinaryReader(bytes); @@ -343,6 +343,14 @@ class RiveFile { ObjectGenerator? objectGenerator, bool loadCdnAssets = true, }) { + // TODO: in the next major version add an assert here to make this a + // requirement + if (!_initializedText) { + debugPrint('''Rive: RiveFile.import called before RiveFile.initialize() + +Consider calling `await RiveFile.initialize()` before using `RiveFile.import`'''); + } + var reader = BinaryReader(bytes); return RiveFile._( reader, @@ -359,8 +367,18 @@ class RiveFile { static bool _initializedText = false; - /// Initialize Rive's text engine if it hasn't been yet. - static Future initializeText() async { + /// Initialize Rive's text, audio, and layout engines. + /// + /// This method is automatically called when using `RiveFile.asset`, + /// `RiveFile.network`, and `RiveFile.file`. + /// + /// When using `RiveFile.import` then `RiveFile.initialize()` should be + /// called manually. + /// + /// Consider calling `unawaited(RiveFile.initialize());` in the `main` method + /// to ensure the engine has initialized before displaying the first Rive + /// graphic. + static Future initialize() async { if (!_initializedText) { final status = await Font.initialize(); if (status == FontInitStatus.success || @@ -370,6 +388,12 @@ class RiveFile { } } + /// Initialize Rive's text engine if it hasn't been yet. + @Deprecated('Use `initialize()` instead') + static Future initializeText() async { + await initialize(); + } + static Future _initTextAndImport( ByteData bytes, { FileAssetLoader? assetLoader, @@ -377,8 +401,8 @@ class RiveFile { ObjectGenerator? objectGenerator, }) async { /// If the file looks like it needs the text runtime, let's load it. - if (!_initializedText && RiveFile.needsTextRuntime(bytes)) { - await initializeText(); + if (!_initializedText) { + await initialize(); } return RiveFile.import( bytes, diff --git a/pubspec.yaml b/pubspec.yaml index 43c5d46..b23e0ab 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: rive -version: 0.13.4 +version: 0.13.5 homepage: https://rive.app description: Rive 2 Flutter Runtime. This package provides runtime functionality for playing back and interacting with animations built with the Rive editor available at https://rive.app. repository: https://github.com/rive-app/rive-flutter