From bf94e7d6b1176db2f8e12968322e67578ff97238 Mon Sep 17 00:00:00 2001 From: HayesGordon Date: Fri, 7 Jun 2024 11:52:32 +0000 Subject: [PATCH] feat: Flutter get component predicate Diffs= 9abd6ee16 feat: Flutter get component predicate (#7388) 8486c3445 Get rid of MetricsPath. (#7371) Co-authored-by: Anurag Devanapally Co-authored-by: Gordon --- .rive_head | 2 +- CHANGELOG.md | 3 + example/lib/example_state_machine.dart | 2 +- example/lib/liquid_download.dart | 2 +- example/lib/little_machine.dart | 2 +- example/lib/state_machine_skills.dart | 2 +- lib/src/rive_core/artboard.dart | 7 ++- pubspec.yaml | 2 +- test/assets/component_discovery.riv | 3 + test/component_find_test.dart | 76 ++++++++++++++++++++++++++ 10 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 test/assets/component_discovery.riv create mode 100644 test/component_find_test.dart diff --git a/.rive_head b/.rive_head index 7c44dc9..014f08f 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -e192d691d2cab253bd2a80f73d9db55f58c45fec +9abd6ee16ca1290488f2bd950844e7730ee92c6e diff --git a/CHANGELOG.md b/CHANGELOG.md index d676b04..babc580 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.13.7 +- Add `getComponentWhereOrNull` on `Artboard`, to find a component that matches the given predicate. This can be used instead of `forEachComponent` as it allows exiting early. + ## 0.13.6 - Add `getBoolInput(name, path)`, `getTriggerInput(name, path)`, and `getNumberInput(name, path` on `Artboard` to set nested inputs (inputs on nested artboards), see [the documentation](https://rive.app/community/doc/state-machines/docxeznG7iiK#nested-inputs). diff --git a/example/lib/example_state_machine.dart b/example/lib/example_state_machine.dart index cec4565..451ee99 100644 --- a/example/lib/example_state_machine.dart +++ b/example/lib/example_state_machine.dart @@ -27,7 +27,7 @@ class _ExampleStateMachineState extends State { // The artboard is the root of the animation and gets drawn in the // Rive widget. - final artboard = riveFile.mainArtboard; + final artboard = riveFile.mainArtboard.instance(); var controller = StateMachineController.fromArtboard(artboard, 'Button'); if (controller != null) { artboard.addController(controller); diff --git a/example/lib/liquid_download.dart b/example/lib/liquid_download.dart index e34956f..cd8f89d 100644 --- a/example/lib/liquid_download.dart +++ b/example/lib/liquid_download.dart @@ -25,7 +25,7 @@ class _LiquidDownloadState extends State { 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; + final artboard = file.mainArtboard.instance(); var controller = StateMachineController.fromArtboard(artboard, 'Download'); if (controller != null) { artboard.addController(controller); diff --git a/example/lib/little_machine.dart b/example/lib/little_machine.dart index 35caa0a..ee3c143 100644 --- a/example/lib/little_machine.dart +++ b/example/lib/little_machine.dart @@ -27,7 +27,7 @@ class _LittleMachineState extends State { // The artboard is the root of the animation and gets drawn in the // Rive widget. - final artboard = file.mainArtboard; + final artboard = file.mainArtboard.instance(); var controller = StateMachineController.fromArtboard( artboard, 'State Machine 1', diff --git a/example/lib/state_machine_skills.dart b/example/lib/state_machine_skills.dart index dccf144..5abbeb4 100644 --- a/example/lib/state_machine_skills.dart +++ b/example/lib/state_machine_skills.dart @@ -25,7 +25,7 @@ class _StateMachineSkillsState extends State { // The artboard is the root of the animation and gets drawn in the // Rive widget. - final artboard = file.mainArtboard; + final artboard = file.mainArtboard.instance(); var controller = StateMachineController.fromArtboard(artboard, 'Designer\'s Test'); if (controller != null) { diff --git a/lib/src/rive_core/artboard.dart b/lib/src/rive_core/artboard.dart index 1617a40..431f1a4 100644 --- a/lib/src/rive_core/artboard.dart +++ b/lib/src/rive_core/artboard.dart @@ -115,8 +115,13 @@ class Artboard extends ArtboardBase with ShapePaintContainer { /// Find a component of a specific type with a specific name. T? component(String name) { + return getComponentWhereOrNull((component) => component.name == name); + } + + /// Find a component that matches the given predicate. + T? getComponentWhereOrNull(bool Function(Component) callback) { for (final component in _components) { - if (component is T && component.name == name) { + if (component is T && callback(component)) { return component as T; } } diff --git a/pubspec.yaml b/pubspec.yaml index 5e8221d..386b1be 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: rive -version: 0.13.6 +version: 0.13.7 homepage: https://rive.app description: Rive 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 diff --git a/test/assets/component_discovery.riv b/test/assets/component_discovery.riv new file mode 100644 index 0000000..67c978f --- /dev/null +++ b/test/assets/component_discovery.riv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d09c9d88024d7944c231e4d8b6509040fa7d68219c06ba0730fed077834f8eeb +size 806088 diff --git a/test/component_find_test.dart b/test/component_find_test.dart new file mode 100644 index 0000000..558eee1 --- /dev/null +++ b/test/component_find_test.dart @@ -0,0 +1,76 @@ +// ignore_for_file: deprecated_member_use_from_same_package + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:rive/rive.dart'; + +import 'src/utils.dart'; + +class MockAssetBundle extends Mock implements AssetBundle {} + +void main() { + setUpAll(() {}); + group("Test finding components on artboard", () { + test('Find a component of a specific type with a specific name.', () async { + final riveBytes = loadFile('assets/component_discovery.riv'); + final riveFile = RiveFile.import(riveBytes); + final artboard = riveFile.mainArtboard.instance(); + + final nestedArtboard = + artboard.component("NestedArtboardFindMe"); + expect(nestedArtboard, isNotNull); + expect(nestedArtboard!.name, "NestedArtboardFindMe"); + + final textRun = artboard.component("TextRunFindMe"); + expect(textRun, isNotNull); + expect(textRun!.name, "TextRunFindMe"); + + final shapeEllipse = artboard.component("EllipseFindMe"); + expect(shapeEllipse, isNotNull); + expect(shapeEllipse!.name, "EllipseFindMe"); + + final shapeRectangle = artboard.component("RectangleFindMe"); + expect(shapeRectangle, isNotNull); + expect(shapeRectangle!.name, "RectangleFindMe"); + + final notFoundComponent = artboard.component("DoesNotExist"); + expect(notFoundComponent, isNull); + }); + + test('Get a component that matches the given predicate', () async { + final riveBytes = loadFile('assets/component_discovery.riv'); + final riveFile = RiveFile.import(riveBytes); + final artboard = riveFile.mainArtboard.instance(); + + final nestedArtboard = + artboard.getComponentWhereOrNull( + (component) => component.name.startsWith("NestedArtboard")); + + expect(nestedArtboard, isNotNull); + expect(nestedArtboard!.name, "NestedArtboardFindMe"); + + final textRun = artboard.getComponentWhereOrNull( + (component) => component.name.startsWith("TextRun")); + + expect(textRun, isNotNull); + expect(textRun!.name, "TextRunFindMe"); + + final shapeEllipse = artboard.getComponentWhereOrNull( + (component) => component.name.startsWith("Ellipse")); + + expect(shapeEllipse, isNotNull); + expect(shapeEllipse!.name, "EllipseFindMe"); + + final shapeRectangle = artboard.getComponentWhereOrNull( + (component) => component.name.startsWith("Rectangle")); + + expect(shapeRectangle, isNotNull); + expect(shapeRectangle!.name, "RectangleFindMe"); + + final notFoundComponent = artboard.getComponentWhereOrNull( + (component) => component.name.startsWith("DoesNotExist")); + expect(notFoundComponent, isNull); + }); + }); +}