Line data Source code
1 : import 'dart:async'; 2 : 3 : import 'package:flutter/widgets.dart'; 4 : import 'package:meedu/rx.dart'; 5 : 6 : import '../utils/ambiguate.dart'; 7 : 8 : /// A widget to be used with Observables (instances of Rx) 9 : /// 10 : /// ```dart 11 : /// import 'package:flutter/material.dart'; 12 : /// import 'package:flutter_meedu/meedu.dart'; 13 : /// import 'package:flutter_meedu/rx.dart'; 14 : /// 15 : /// class RxPage extends StatefulWidget { 16 : /// @override 17 : /// _RxPageState createState() => _RxPageState(); 18 : /// } 19 : /// 20 : /// class _RxPageState extends State<RxPage> { 21 : /// final _counter = Rx<int>(0); // create an observable 22 : /// 23 : /// @override 24 : /// void dispose() { 25 : /// _counter.close(); // You must call to close when you don't need the observable any more 26 : /// super.dispose(); 27 : /// } 28 : /// 29 : /// @override 30 : /// Widget build(BuildContext context) { 31 : /// return Scaffold( 32 : /// body: Center( 33 : /// child: RxBuilder( 34 : /// (_) => Text("${_counter.value}"), 35 : /// ), 36 : /// ), 37 : /// floatingActionButton: FloatingActionButton( 38 : /// onPressed: () { 39 : /// _counter.value++; 40 : /// }, 41 : /// ), 42 : /// ); 43 : /// } 44 : /// } 45 : /// ``` 46 : class RxBuilder extends StatefulWidget { 47 : // ignore: public_member_api_docs 48 2 : RxBuilder(this.builder, {Key? key}) : super(key: key); 49 : 50 : /// the builder function 51 : final Widget Function(BuildContext context) builder; 52 : 53 1 : @override 54 1 : _RxBuilderState createState() => _RxBuilderState(); 55 : } 56 : 57 : class _RxBuilderState extends State<RxBuilder> { 58 1 : _RxBuilderState() { 59 2 : _observer = RxNotifier(); 60 : } 61 : 62 : RxNotifier? _observer; 63 : late StreamSubscription _subscription; 64 : bool _afterFirstLayout = false; 65 : 66 1 : @override 67 : void initState() { 68 1 : super.initState(); 69 5 : ambiguate(WidgetsBinding.instance)?.endOfFrame.then((_) { 70 1 : _afterFirstLayout = true; 71 : }); 72 : // listen the observable events 73 4 : _subscription = _observer!.listen(_rebuild); 74 : } 75 : 76 1 : @override 77 : void dispose() { 78 1 : _afterFirstLayout = false; 79 : // remove the subsciptions when the widget is destroyed 80 2 : _subscription.cancel(); 81 2 : _observer?.close(); 82 1 : super.dispose(); 83 : } 84 : 85 1 : void _rebuild(_) { 86 2 : if (_afterFirstLayout && mounted) { 87 2 : setState(() {}); 88 : } 89 : } 90 : 91 1 : @override 92 : Widget build(BuildContext context) { 93 : final observer = RxNotifier.proxy; 94 : 95 1 : RxNotifier.proxy = _observer; 96 3 : final result = widget.builder(context); 97 2 : if (!_observer!.canUpdate) { 98 0 : throw FlutterError( 99 : ''' 100 : If you are seeing this error, you probably did not insert any observable variables into RxBuilder 101 : ''', 102 : ); 103 : } 104 : RxNotifier.proxy = observer; 105 : return result; 106 : } 107 : }