stator 0.0.24 stator: ^0.0.24 copied to clipboard
Stator: Effortless Flutter State Management, Scale with Ease.
Stator #
An easy to use state management library for Flutter.
Example #
// Run the this example, play around with it, then take a look at the code to have a better understanding.
// Made by Jehad Hmoudah
import 'package:flutter/material.dart';
import 'package:stator/stator.dart';
void main() {
// isDebuggingEnabled is true by default.
// This line is here just to show that you can disable debugging.
Stators.isDebuggingEnabled = true;
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Stator Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
initialRoute: "/",
routes: {
"/": (context) => const HomePage(),
"/profile-details": (context) => const ProfileDetails(),
"/profile-setup": (context) => const ProfileSetup(),
},
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("HomePage - Stator Demo"),
),
body: Center(
child: FilledButton(
onPressed: () => Navigator.pushNamed(context, "/profile-details"),
child: const Text("Profile Details"),
),
),
);
}
}
class ProfileDetailsStator with StatorMixin<ProfileDetails> {
// You can use BehaviorSubject from RxDart or ValueNotifier instead of StateVar.
final name = StateVar("Jehad");
final major = StateVar("Computer Engineering");
final age = StateVar("20");
}
class ProfileDetails extends StatefulWidget {
const ProfileDetails({super.key});
@override
State<ProfileDetails> createState() => _ProfileDetailsState();
}
class _ProfileDetailsState extends State<ProfileDetails>
with WidgetStatorMixin<ProfileDetails, ProfileDetailsStator> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Profile Details"),
),
body: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ValueListenableBuilder(
valueListenable: stator.name,
builder: (context, value, child) => Text(
"Name: ${stator.name.value}",
style: Theme.of(context).textTheme.headlineSmall,
),
),
ValueListenableBuilder(
valueListenable: stator.major,
builder: (context, value, child) => Text(
"Major: ${stator.major.value}",
style: Theme.of(context).textTheme.headlineSmall,
),
),
ValueListenableBuilder(
valueListenable: stator.age,
builder: (context, value, child) => Text(
"Age: ${stator.age.value}",
style: Theme.of(context).textTheme.headlineSmall,
),
),
const SizedBox(height: 10),
SizedBox(
width: double.infinity,
child: FilledButton(
onPressed: () =>
Navigator.pushNamed(context, "/profile-setup"),
child: const Text("Profile Setup"),
),
),
],
),
),
),
);
}
@override
// You can use instanceName to register multiple instances of
// ProfileDetailsStator, e.g. if you have multiple users with
// different IDs use the ID of each user as the instanceName.
get config => Stator(() => ProfileDetailsStator());
}
class ProfileSetup extends StatefulWidget {
const ProfileSetup({super.key});
@override
State<ProfileSetup> createState() => _ProfileSetupState();
}
class _ProfileSetupState extends State<ProfileSetup> {
// The object ProfileDetailsStator() inside
// useStator(() => ProfileDetailsStator()) won't be used
// unless ProfileDetailsStator() hasn't been registered before.
// Don't use late modifier and avoid using useStator inside initState.
final statorOfProfileDetails = useStator(() => ProfileDetailsStator());
// ScrollControllers must be initialized and
// disposed inside stateful widget not inside a Stator.
late final ScrollController scrollController;
// TextEditingControllers can be initialized and disposed either
// in a Stator or in a stateful widget, depending on how they
// get used throughout the app.
late final nameController =
TextEditingController(text: statorOfProfileDetails.name.value);
late final majorController =
TextEditingController(text: statorOfProfileDetails.major.value);
late final ageController =
TextEditingController(text: statorOfProfileDetails.age.value);
@override
void initState() {
super.initState();
scrollController = ScrollController();
}
@override
void dispose() {
// You must disuse Stators of other screens so that automatic
// unregistering works correctly.
disuseStator<ProfileDetailsStator>();
scrollController.dispose();
nameController.dispose();
majorController.dispose();
ageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
appBar: AppBar(
title: const Text("Profile Setup"),
),
body: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16),
controller: scrollController,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"State/Data is synced between Profile Details screen and all Profile Setup screens.",
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
ValueListenableBuilder(
builder: (context, value, child) {
nameController.text = statorOfProfileDetails.name.value;
return TextField(
controller: nameController,
decoration: const InputDecoration(
filled: true,
labelText: "Age",
),
onChanged: (value) =>
statorOfProfileDetails.name.value = value,
);
},
valueListenable: statorOfProfileDetails.name,
),
const SizedBox(height: 10),
ValueListenableBuilder(
builder: (context, value, child) {
majorController.text = statorOfProfileDetails.major.value;
return TextField(
controller: majorController,
decoration: const InputDecoration(
filled: true,
labelText: "Age",
),
onChanged: (value) =>
statorOfProfileDetails.major.value = value,
);
},
valueListenable: statorOfProfileDetails.major,
),
const SizedBox(height: 10),
ValueListenableBuilder(
builder: (context, value, child) {
ageController.text = statorOfProfileDetails.age.value;
return TextField(
controller: ageController,
decoration: const InputDecoration(
filled: true,
labelText: "Age",
),
onChanged: (value) =>
statorOfProfileDetails.age.value = value,
);
},
valueListenable: statorOfProfileDetails.age,
),
const SizedBox(height: 10),
FilledButton(
onPressed: () =>
Navigator.pushNamed(context, "/profile-setup"),
child: const Text("Push Another Profile Setup"),
),
const SizedBox(height: 10),
const Text(
"Each time you push a new Profile Setup screen the widgetsUsingThisStator gets incremented.\n You can see that in your console/terminal.",
textAlign: TextAlign.center,
),
],
),
),
),
),
);
}
}