import 'package:flutter/widgets.dart'; /// Listening to multiple dependencies at the same time causes firing an event for all dependencies /// even though some of them didn't change: /// ```dart /// @override /// void didChangeDependencies() { /// super.didChangeDependencies(); /// _bloc.add(EquipmentProfileChangedEvent(EquipmentProfile.of(context))); /// if (!MeteringScreenLayout.featureStatusOf(context, MeteringScreenLayoutFeature.filmPicker)) { /// _bloc.add(const FilmChangedEvent(Film.other())); /// } /// } /// ``` /// To overcome this issue I've decided to create a generic listener, /// that will listen to each dependency separately. class InheritedWidgetListener extends StatefulWidget { final ValueChanged onDidChangeDependencies; final Widget child; const InheritedWidgetListener({ required this.onDidChangeDependencies, required this.child, super.key, }); @override State> createState() => _InheritedWidgetListenerState(); } class _InheritedWidgetListenerState extends State> { @override void didChangeDependencies() { super.didChangeDependencies(); widget.onDidChangeDependencies(context.listen()); } @override Widget build(BuildContext context) { return widget.child; } } class InheritedWidgetBase extends InheritedWidget { final T data; const InheritedWidgetBase({ required this.data, required super.child, super.key, }); static T of(BuildContext context, {bool listen = true}) { if (listen) { return context.dependOnInheritedWidgetOfExactType>()!.data; } else { return context.findAncestorWidgetOfExactType>()!.data; } } @override bool updateShouldNotify(InheritedWidgetBase oldWidget) => true; } extension InheritedWidgetBaseContext on BuildContext { T get() { return InheritedWidgetBase.of(this, listen: false); } T listen() { return InheritedWidgetBase.of(this); } } /// Listening to multiple dependencies at the same time causes firing an event for all dependencies /// even though some of them didn't change: /// ```dart /// @override /// void didChangeDependencies() { /// super.didChangeDependencies(); /// _bloc.add(EquipmentProfileChangedEvent(EquipmentProfile.of(context))); /// if (!MeteringScreenLayout.featureStatusOf(context, MeteringScreenLayoutFeature.filmPicker)) { /// _bloc.add(const FilmChangedEvent(Film.other())); /// } /// } /// ``` /// To overcome this issue I've decided to create a generic listener, /// that will listen to each dependency separately. class InheritedModelAspectListener extends StatefulWidget { final A aspect; final ValueChanged onDidChangeDependencies; final Widget child; const InheritedModelAspectListener({ required this.aspect, required this.onDidChangeDependencies, required this.child, super.key, }); @override State> createState() => _InheritedModelAspectListenerState(); } class _InheritedModelAspectListenerState extends State> { @override void didChangeDependencies() { super.didChangeDependencies(); widget.onDidChangeDependencies(context.listenModelFeature(widget.aspect)); } @override Widget build(BuildContext context) { return widget.child; } } class InheritedModelBase extends InheritedModel { final Map data; const InheritedModelBase({ required this.data, required super.child, super.key, }); static Map of(BuildContext context, {bool listen = true}) { if (listen) { return context.dependOnInheritedWidgetOfExactType>()!.data; } else { return context.findAncestorWidgetOfExactType>()!.data; } } static T featureOf(BuildContext context, A aspect) { return InheritedModel.inheritFrom>(context, aspect: aspect)! .data[aspect]!; } @override bool updateShouldNotify(InheritedModelBase oldWidget) => true; @override bool updateShouldNotifyDependent( InheritedModelBase oldWidget, Set dependencies, ) { for (final dependecy in dependencies) { if (oldWidget.data[dependecy] != data[dependecy]) { return true; } } return false; } } extension InheritedModelBaseContext on BuildContext { Map getModel() { return InheritedModelBase.of(this, listen: false); } Map listenModel() { return InheritedModelBase.of(this); } T listenModelFeature(A aspect) { return InheritedModelBase.featureOf(this, aspect); } }