Flutter Mediator | Global Mode + Model Mode | |||
Lite | Global Mode only | |||
Persistence | Lite + Persistence | |||
Example | Logins to a REST server with i18n, theming, persistence and state management. |
Flutter Mediator Lite is a super easy state management package, base on the InheritedModel with automatic aspect management to make it simpler and easier to use and rebuild widgets only when necessary.
Flutter Mediator Lite is derived from Flutter Mediator v2.1.3, and consists only of the Global Mode.
- Flutter Mediator Lite
Add the following dependency to pubspec.yaml of your flutter project:
dependencies:
flutter_mediator_lite: "^1.0.3"
Import flutter_mediator_lite in files that will be used:
import 'package:flutter_mediator_lite/mediator.dart';
For help getting started with Flutter, view the online documentation.
-
Declare the watched variable with
globalWatch
.
Suggest to put the watched variables into a file var.dart and then import it. -
Create the host with
globalHost
at the top of the widget tree. -
Create a consume widget with
globalConsume
orwatchedVar.consume
to register the watched variable to the host to rebuild it when updating. -
Make an update to the watched variable, by
watchedVar.value
orwatchedVar.ob.updateMethod(...)
.
Step 1: Declare variable in var.dart.
//* Step1: Declare the watched variable with `globalWatch`
//* in the var.dart and then import it.
final touchCount = globalWatch(0);
Step 2: Initialize the persistent watched variable and create the Host
.
Future<void> main() async {
//* Initialize the persistent watched variables
//* whose value is stored by the SharedPreferences.
await initVars();
runApp(
//* Step2: Create the host with `globalHost`
//* at the top of the widget tree.
globalHost(
child: MyApp(),
),
);
}
Step 3: Create a consume widget.
Scaffold(
appBar: AppBar(title: const Text('Int Demo')),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('You have pushed the button this many times:'),
//* Step3: Create a consume widget with
//* `globalConsume` or `watchedVar.consume` to register the
//* watched variable to the host to rebuild it when updating.
globalConsume(
() => Text(
'${touchCount.value}',
style: Theme.of(context).textTheme.headlineMedium,
),
),
// ...
Step 4: Implement update function.
FloatingActionButton(
//* Stet4: Make an update to the watched variable.
onPressed: () => touchCount.value++,
tooltip: 'Increment',
child: const Icon(Icons.add),
heroTag: null,
),
example/lib/pages/list_page.dart
Step 1: Declare variable in var.dart.
//* Step1: Declare the watched variable with `globalWatch` in the var.dart.
//* And then import it in the file.
final data = globalWatch(<ListItem>[]);
Step 3: Create consume widget.
return Scaffold(
appBar: AppBar(title: const Text('List Demo')),
//* Step3: Create a consume widget with
//* `globalConsume` or `watchedVar.consume` to register the
//* watched variable to the host to rebuild it when updating.
body: globalConsume(
() => GridView.builder(
itemCount: data.value.length,
// ...
Step 4: Implement update function.
void updateListItem() {
// ...
//* Step4: Make an update to the watched variable.
//* watchedVar.ob = watchedVar.notify() and then return the underlying object
data.ob.add(ListItem(itemName, units, color));
}
Or use Flutter Mediator Persistence for built in persistence support.
Please see Flutter Mediator Persistence: use case 3 for details.
example/lib/pages/locale_page.dart
Step 1-1: Declare variable in var.dart.
//* Declare a global scope SharedPreferences.
late SharedPreferences prefs;
//* Step1B: Declare the persistent watched variable with `late Rx<Type>`
//* And then import it in the file.
const DefaultLocale = 'en';
late Rx<String> locale; // local_page.dart
/// Initialize the persistent watched variables
/// whose value is stored by the SharedPreferences.
Future<void> initVars() async {
// To make sure SharedPreferences works.
WidgetsFlutterBinding.ensureInitialized();
prefs = await SharedPreferences.getInstance();
locale = globalWatch(prefs.getString('locale') ?? DefaultLocale);
}
Step 1-2: Initialize the persistent watched variables in main.dart.
Future<void> main() async {
//* Step1-2: Initialize the persistent watched variables
//* whose value is stored by the SharedPreferences.
await initVars();
runApp(
// ...
);
}
Step 1-3: Initialize the locale in main.dart.
//* Initialize the locale with the persistent value.
localizationsDelegates: [
FlutterI18nDelegate(
translationLoader: FileTranslationLoader(
forcedLocale: Locale(locale.value),
fallbackFile: DefaultLocale,
// ...
),
// ...
),
],
Step 1-4: Add assets in pubspec.yaml and prepare locale files in the folder
flutter:
# ...
assets:
- assets/images/
- assets/flutter_i18n/
Step 3: Create consume widget
return SizedBox(
child: Row(
children: [
//* Step3: Create a consume widget with
//* `globalConsume` or `watchedVar.consume` to register the
//* watched variable to the host to rebuild it when updating.
//* `watchedVar.consume()` is a helper function to
//* `touch()` itself first and then `globalConsume`.
locale.consume(() => Text('${'app.hello'.i18n(context)} ')),
Text('$name, '),
//* Or use the ci18n extension
'app.thanks'.ci18n(context),
// ...
],
),
);
Step 4: Implement update function in var.dart.
Future<void> changeLocale(BuildContext context, String countryCode) async {
if (countryCode != locale.value) {
final loc = Locale(countryCode);
await FlutterI18n.refresh(context, loc);
//* Step4: Make an update to the watched variable.
locale.value = countryCode; // will rebuild the registered widget
await prefs.setString('locale', countryCode);
}
}
example/lib/pages/scroll_page.dart
Step 1: Declare variable in var.dart.
//* Step1: Declare the watched variable with `globalWatch` in the var.dart.
//* And then import it in the file.
final opacityValue = globalWatch(0.0);
Step 3: Create consume widget.
class CustomAppBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
//* Step3: Create a consume widget with
//* `globalConsume` or `watchedVar.consume` to register the
//* watched variable to the host to rebuild it when updating.
return globalConsume(
() => Container(
color: Colors.black.withOpacity(opacityValue.value),
// ...
),
);
}
}
Step 4: Add an offset change listener.
class _ScrollPageState extends State<ScrollPage> {
// ...
@override
void initState() {
_scrollController.addListener(() {
//* Step4: Make an update to the watched variable.
opacityValue.value =
(_scrollController.offset / 350).clamp(0, 1).toDouble();
});
super.initState();
}
-
At step 1,
globalWatch(variable)
creates a watched variable from the variable. -
At step 3, create a consume widget and register it to the host to rebuild it when updating,
useglobalConsume(() => widget)
if the value of the watched variable is used inside the consume widget;
or usewatchedVar.consume(() => widget)
totouch()
the watched variable itself first and thenglobalConsume(() => widget)
. -
At step 4, update to the
watchedVar.value
will notify the host to rebuild; or the underlying object would be a class, then usewatchedVar.ob.updateMethod(...)
to notify the host to rebuild.watchedVar.ob = watchedVar.notify() and then return the underlying object
.
Note: Suggest to put the watched variables into a file var.dart and then import it.
globalGet<T>({Object? tag})
to retrieve the watched variable from another file.
-
With
globalWatch(variable)
, the watched variable will be retrieved by theType
of the variable, i.e. retrieve byglobalGet<Type>()
. -
With
globalWatch(variable, tag: object)
, the watched variable will be retrieved by the tag, i.e. retrieve byglobalGet(tag: object)
.
//* Step1: Declare the watched variable with `globalWatch`.
final touchCount = globalWatch(0);
lib/pages/locale_page.dart
example/lib/pages/locale_page.dart
class LocalePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
//* Get the watched variable by it's [Type] from `../main.dart`
final mainInt = globalGet<int>();
return Container(
// ...
const SizedBox(height: 25),
//* `globalConsume` the watched variable from `../main.dart`
globalConsume(
() => Text(
'You have pressed the button at the first page ${mainInt.value} times',
),
// ...
//* Step1: Declare the watched variable with `globalWatch`.
final touchCount = globalWatch(0, tag: 'tagCount');
lib/pages/locale_page.dart
example/lib/pages/locale_page.dart
class LocalePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
//* Get the watched variable by [tag] from `../main.dart`
final mainInt = globalGet('tagCount');
return Container(
// ...
const SizedBox(height: 25),
//* `globalConsume` the watched variable from `../main.dart`
globalConsume(
() => Text(
'You have pressed the button at the first page ${mainInt.value} times',
),
// ...
-
Make sure the watched variable is initialized, only after the page is loaded.
-
When using
Type
to retrieve the watched variable, only the first one of theType
is returned.
globalBroadcast()
, to broadcast to all the consume widgets.globalConsumeAll(Widget Function() create, {Key? key})
, to create a consume widget which will be rebuilt whenever any watched variables changes are made.globalFrameAspects
, a getter, to return the updated aspects.globalAllAspects
, a getter, to return all the aspects that has been registered.
- Flutter Mediator: Global Mode + Model Mode.
- Lite: Global Mode only.
- Persistence: Lite + built in persistence.
A boilerplate example that logins to a REST server with i18n, theming, persistence and state management.
Please see the login to a REST server example for details.
InheritedModel provides an aspect parameter to its descendants to indicate which fields they care about to determine whether that widget needs to rebuild. InheritedModel can help you rebuild its descendants only when necessary.
Please see the Changelog page.
Flutter Mediator Lite is distributed under the MIT License. See LICENSE for more information.