import 'package:bloc/bloc.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:rive/rive.dart'; enum LoaderFlavour { small(filepath: 'assets/animations/loaders/small_loader.riv'), big(filepath: 'assets/animations/big_loaders/big_logo_splash.riv'); const LoaderFlavour({required this.filepath}); final String filepath; } class LoaderController extends Cubit { LoaderController() : super(false); void show() => emit(true); void hide() => emit(false); } class Loader extends HookWidget { final LoaderFlavour flavour; final Fit fit; final LoaderController controller; const Loader( this.controller, { super.key, required this.flavour, this.fit = Fit.contain, }); Loader.playing({required LoaderFlavour flavour, Fit fit = Fit.contain}) : this(LoaderController()..show(), flavour: flavour, fit: fit); Loader.stopped({required LoaderFlavour flavour, Fit fit = Fit.contain}) : this(LoaderController()..hide(), flavour: flavour, fit: fit); @override Widget build(BuildContext context) { final animFile = useMemoized( () => FileLoader.fromAsset("packages/mtcore/${flavour.filepath}", riveFactory: Factory.flutter), ); return RiveWidgetBuilder( fileLoader: animFile, builder: (context, state) { switch (state) { case RiveLoading(): return const Center(child: CircularProgressIndicator()); case RiveFailed(): final message = state.error.toString(); return ErrorWidget.withDetails( message: message, error: FlutterError(message), ); case RiveLoaded(:final file): final controller = RiveWidgetController( file, stateMachineSelector: StateMachineSelector.byIndex(0), ); controller.active = this.controller.state; this.controller.stream.listen((toggle) { controller.active = toggle; }); return RiveWidget(controller: controller, fit: fit); } }, ); } }