diff --git a/.rive_head b/.rive_head index 25a3e83..1d24b7f 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -913760d979f6ab9b54ac510726649dc0980f6b15 +66e234066f31e22208005a4583b4f423a86c4281 diff --git a/CHANGELOG.md b/CHANGELOG.md index cfd69f3..dea2365 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.11.9 + +- Fix issue showing text when the default font is not available at `assets/fonts/Inter-Regular.ttf`. We will set first valid font we encounter in a rive file as default font instead. + ## 0.11.8 - Fix text origin changing updating text offset. diff --git a/example/assets/text_flutter.riv b/example/assets/text_flutter.riv new file mode 100644 index 0000000..d14938d Binary files /dev/null and b/example/assets/text_flutter.riv differ diff --git a/example/lib/basic_text.dart b/example/lib/basic_text.dart new file mode 100644 index 0000000..5c8af76 --- /dev/null +++ b/example/lib/basic_text.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:rive/rive.dart'; + +/// Basic example playing a Rive animation from a packaged asset. +class BasicText extends StatelessWidget { + const BasicText({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Basic Text'), + ), + body: const Center( + child: RiveAnimation.asset( + 'assets/text_flutter.riv', + fit: BoxFit.cover, + ), + ), + ); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 9c9240a..0c8ebfb 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -15,6 +15,7 @@ import 'package:rive_example/simple_machine_listener.dart'; import 'package:rive_example/simple_state_machine.dart'; 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( @@ -54,6 +55,7 @@ class _RiveExampleAppState extends State { const _Page('State Machine with Listener', StateMachineListener()), const _Page('Skinning Demo', SkinningDemo()), const _Page('Animation Carousel', AnimationCarousel()), + const _Page('Basic Text', BasicText()), const _Page('Custom Asset Loading', CustomAssetLoading()), const _Page('Custom Cached Asset Loading', CustomCachedAssetLoading()), ]; diff --git a/lib/src/asset_loader.dart b/lib/src/asset_loader.dart index c2768dc..9f80e75 100644 --- a/lib/src/asset_loader.dart +++ b/lib/src/asset_loader.dart @@ -1,7 +1,7 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; import 'package:rive/src/asset.dart'; +import 'package:rive/src/debug.dart'; import 'package:rive/src/rive_core/assets/file_asset.dart'; import 'package:rive/src/utilities/utilities.dart'; @@ -49,13 +49,11 @@ class CDNAssetLoader extends FileAssetLoader { Uint8List.view(res.bodyBytes.buffer), ); } on Exception catch (e) { - // only print in debug - assert(() { - debugPrint('''Unable to parse response ${asset.runtimeType}. + printDebugMessage( + '''Unable to parse response ${asset.runtimeType}. - Url: $url - - Exception: $e'''); - return true; - }()); + - Exception: $e''', + ); return false; } diff --git a/lib/src/core/importers/file_asset_importer.dart b/lib/src/core/importers/file_asset_importer.dart index f32db1c..1d931b0 100644 --- a/lib/src/core/importers/file_asset_importer.dart +++ b/lib/src/core/importers/file_asset_importer.dart @@ -1,5 +1,6 @@ import 'package:rive/src/asset_loader.dart'; import 'package:rive/src/core/core.dart'; +import 'package:rive/src/debug.dart'; import 'package:rive/src/rive_core/assets/file_asset.dart'; import 'package:rive/src/rive_core/assets/file_asset_contents.dart'; @@ -35,15 +36,13 @@ class FileAssetImporter extends ImportStackObject { // try to get them out of band assetLoader?.load(fileAsset).then((loaded) { // TODO: improve error logging - // Only print if in debug mode. - assert(() { - if (!loaded) { - debugPrint('''Rive asset (${fileAsset.name}) was not able to load: + if (!loaded) { + printDebugMessage( + '''Rive asset (${fileAsset.name}) was not able to load: - Unique file name: ${fileAsset.uniqueFilename} - - Asset id: ${fileAsset.id}'''); - } - return true; - }()); + - Asset id: ${fileAsset.id}''', + ); + } }); } return super.resolve(); diff --git a/lib/src/debug.dart b/lib/src/debug.dart new file mode 100644 index 0000000..8d92f07 --- /dev/null +++ b/lib/src/debug.dart @@ -0,0 +1,9 @@ +import 'package:flutter/foundation.dart'; + +/// Print a message only when running in debug. +void printDebugMessage(String message) { + assert(() { + debugPrint(message); + return true; + }()); +} diff --git a/lib/src/rive_core/text/text.dart b/lib/src/rive_core/text/text.dart index b091ca2..e9ec9cc 100644 --- a/lib/src/rive_core/text/text.dart +++ b/lib/src/rive_core/text/text.dart @@ -3,6 +3,7 @@ import 'dart:typed_data'; import 'dart:ui'; import 'package:flutter/services.dart'; +import 'package:rive/src/debug.dart'; import 'package:rive/src/generated/text/text_base.dart'; import 'package:rive/src/rive_core/component_dirt.dart'; import 'package:rive/src/rive_core/text/styled_text.dart'; @@ -77,6 +78,15 @@ class Text extends TextBase with TextStyleContainer { int get unicharCount => _unicharCount; + Font? getFirstAvailableFont() { + for (final run in runs) { + if (run.style?.font != null) { + return run.style?.font; + } + } + return null; + } + StyledText makeStyled( Font defaultFont, { bool forEditing = false, @@ -179,7 +189,6 @@ class Text extends TextBase with TextStyleContainer { _syncRuns(); } - Mat2D get originTransform => Mat2D.multiply( Mat2D(), worldTransform, @@ -472,6 +481,9 @@ class Text extends TextBase with TextStyleContainer { return; } + + // Question (max): is it safer to simply skip computing Shape if we + // have no default font? assert(_defaultFont != null); var defaultFont = _defaultFont!; _modifierShape?.dispose(); @@ -539,6 +551,11 @@ class Text extends TextBase with TextStyleContainer { _defaultFont = Font.decode(fontAsset.buffer.asUint8List()); // Reshape now that we have font. markShapeDirty(); + }).onError((error, stackTrace) { + _defaultFont = getFirstAvailableFont(); + if (_defaultFont != null) { + markShapeDirty(); + } }); } else { computeShape();