Files
ux/lib/src/reactive/future_reactive_builder.dart
agra d68a2978eb ux: bulk WIP — UxPlugin→XPlugin rename + new anim/core/navi/reactive packages
Catch-all commit for outstanding pre-existing local changes. Mixes
several themes that would normally be split:

- Rename: UxPlugin → XPlugin across iOS, macOS, Android registrants.
- New top-level packages under lib/src/: anim/ (animated values,
  panes, sheets, dock, measured), core/ (Emitter, ReactiveBuilder
  scaffolding, presenter/widget/value/dispose primitives), navi/
  (Screen/ScreenStack/Router/hero/transitions), reactive/.
- Edits across existing plugins (clipboard, crash, file, gallery,
  keyboard, scanner, sensor, url) to align with the new core.
- Test updates and CHANGELOG/README touches accompanying the above.
2026-05-21 08:58:07 +03:00

87 lines
2.0 KiB
Dart

import 'package:flutter/widgets.dart';
import 'package:ux/src/reactive/reactive.dart';
/// Awaits an async creation of a [Reactive] and rebuilds on its changes.
///
/// {@tool snippet}
/// Lazy async loading of a bloc.
/// ```dart
/// FutureReactiveBuilder<CounterState>(
/// future: (ctx) async => CounterBloc()..increment(),
/// builder: (_, state, __) => Text('Loaded: \\${state.count}'),
/// );
/// ```
/// {@end-tool}
class FutureReactiveBuilder<T> extends StatefulWidget {
const FutureReactiveBuilder({
required this.future,
required this.builder,
this.child,
Key? key,
}) : super(key: key);
final Widget? child;
/// Async factory returning a [Reactive] instance.
final Future<Reactive<T>> Function(BuildContext context) future;
/// Builder invoked with the current state value once ready.
final Widget Function(BuildContext context, T state, Widget? child) builder;
@override
State<FutureReactiveBuilder<T>> createState() => _FutureReactiveBuilderState<T>();
}
class _FutureReactiveBuilderState<T> extends State<FutureReactiveBuilder<T>> {
@override
void initState() {
super.initState();
_initBloc();
}
Reactive<T>? _bloc;
Future<void> _initBloc() async {
final bloc = await widget.future(context);
bloc.addListener(_notify);
_bloc = bloc;
// notify bloc is ready
_notify();
}
void _notify() => setState(() {});
void _disposeBloc() async {
if (_bloc != null) {
_bloc!
..removeListener(_notify)
..dispose();
_bloc = null;
}
}
@override
void didUpdateWidget(FutureReactiveBuilder<T> oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.future != widget.future ||
oldWidget.builder != widget.builder ||
oldWidget.child != widget.child) {
_disposeBloc();
_initBloc();
}
}
@override
Widget build(BuildContext context) {
return _bloc == null
? SizedBox.shrink()
: widget.builder(
context,
_bloc!.value,
widget.child,
);
}
}