1604008260
A lightweight, yet powerful way to bind your application state with your business logic.
As other state management pattern, binder aims to separate the application state from the business logic that updates it:
We can see the whole application state as the agglomeration of a multitude of tiny states. Each state being independent from each other. A view can be interested in some particular states and has to use a logic component to update them.
In the pubspec.yaml
of your flutter project, add the following dependency:
dependencies:
binder: <latest_version>
In your library add the following import:
import 'package:binder/binder.dart';
Any state has to be declared through a StateRef
with its initial value:
final counterRef = StateRef(0);
Note: A state should be immutable, so that the only way to update it, is through methods provided by this package.
Any logic component has to be declared through a LogicRef
with a function that will be used to create it:
final counterViewLogicRef = LogicRef((scope) => CounterViewLogic(scope));
The scope
argument can then be used by the logic to mutate the state and access other logic components.
Note: You can declare StateRef
and LogicRef
objects as public global variables if you want them to be accessible from other parts of your app.
If we want our CounterViewLogic
to be able to increment our counter state, we might write something like this:
/// A business logic component can apply the [Logic] mixin to have access to
/// useful methods, such as `write` and `read`.
class CounterViewLogic with Logic {
const CounterViewLogic(this.scope);
/// This is the object which is able to interact with other components.
@override
final Scope scope;
/// We can use the [write] method to mutate the state referenced by a
/// [StateRef] and [read] to obtain its current state.
void increment() => write(counterRef, read(counterRef) + 1);
}
In order to bind all of this together in a Flutter app, we have to use a dedicated widget called BinderScope
. This widget is responsible for holding a part of the application state and for providing the logic components. You will typically create this widget above the MaterialApp
widget:
BinderScope(
child: MaterialApp(
home: CounterView(),
),
);
In any widget under the BinderScope
, you can call extension methods on BuildContext
to bind the view to the application state and to the business logic components:
class CounterView extends StatelessWidget {
const CounterView({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
/// We call the [watch] extension method on a [StateRef] to rebuild the
/// widget when the underlaying state changes.
final counter = context.watch(counterRef);
return Scaffold(
appBar: AppBar(title: const Text('Binder example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
Text('$counter', style: Theme.of(context).textTheme.headline4),
],
),
),
floatingActionButton: FloatingActionButton(
/// We call the [use] extension method to get a business logic component
/// and call the appropriate method.
onPressed: () => context.use(counterViewLogicRef).increment(),
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
This is all you need to know for a basic usage.
Note: The whole code for the above snippets is available in the example file.
A state can be of a simple type as an int
or a String
but it can also be more complex, such as the following:
class User {
const User(this.firstName, this.lastName, this.score);
final String firstName;
final String lastName;
final int score;
}
Some views of an application are only interested in some parts of the global state. In these cases, it can be more efficient to select only the part of the state that is useful for these views.
For example, if we have an app bar title which is only responsible for displaying the full name of a User
, and we don’t want it to rebuild every time the score changes, we will use the select
method of the StateRef
to watch only a sub part of the state:
class AppBarTitle extends StatelessWidget {
const AppBarTitle({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
final fullName = context.watch(
userRef.select((user) => '${user.firstName} ${user.lastName}'),
);
return Text(fullName);
}
}
It can be useful to be able to override the initial state of StateRef
or the factory of LogicRef
in some conditions:
Let’s say we want to create an app where a user can create counters and see the sum of all counters:
We could do this by having a global state being a list of integers, and a business logic component for adding counters and increment them:
final countersRef = StateRef(const <int>[]);
final countersLogic = LogicRef((scope) => CountersLogic(scope));
class CountersLogic with Logic {
const CountersLogic(this.scope);
@override
final Scope scope;
void addCounter() {
write(countersRef, read(countersRef).toList()..add(0));
}
void increment(int index) {
final counters = read(countersRef).toList();
counters[index]++;
write(countersRef, counters);
}
}
We can then use the select
extension method in a widget to watch the sum of this list:
final sum = context.watch(countersRef.select(
(counters) => counters.fold<int>(0, (a, b) => a + b),
));
Now, for creating the counter view, we can have an index
parameter in the constructor of this view. This has some drawbacks:
index
for every widget down the tree, up to our child.const
keyword anymore.A better approach would be to create a BinderScope
above each counter widget. We would then configure this BinderScope
to override the state of a StateRef
for its descendants, with a different initial value.
Any StateRef
or LogicRef
can be overriden in a BinderScope
. When looking for the current state, a descendant will get the state of the first reference overriden in a BinderScope
until the root BinderScope
. This can be written like this:
final indexRef = StateRef(0);
class HomeView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final countersCount =
context.watch(countersRef.select((counters) => counters.length));
return Scaffold(
...
child: GridView(
...
children: [
for (int i = 0; i < countersCount; i++)
BinderScope(
overrides: [indexRef.overrideWith(i)],
child: const CounterView(),
),
],
),
...
);
}
}
The BinderScope
constructor has an overrides
parameter which can be supplied from an overrideWith
method on StateRef
and LogicRef
instances.
Note: The whole code for the above snippets is available in the example file.
Let’s say you have an api client in your app:
final apiClientRef = LogicRef((scope) => ApiClient());
If you want to provide a mock instead, while testing, you can do:
testWidgets('Test your view by mocking the api client', (tester) async {
final mockApiClient = MockApiClient();
// Build our app and trigger a frame.
await tester.pumpWidget(
BinderScope(
overrides: [apiClientRef.overrideWith((scope) => mockApiClient)],
child: const MyApp(),
),
);
expect(...);
});
Whenever the apiClientRef
is used in your app, the MockApiClient
instance will be used instead of the real one.
You may encounter a situation where different widgets are interested in a derived state which is computed from different sates. In this situation it can be helpful to have a way to define this derived state globally, so that you don’t have to copy/paste this logic across your widgets. Binder comes with a Computed
class to help you with that use case.
Let’s say you have a list of products referenced by productsRef
, each product has a price, and you can filter these products according to a price range (referenced by minPriceRef
and maxPriceRef
).
You could then define the following Computed
instance:
final filteredProductsRef = Computed((watch) {
final products = watch(productsRef);
final minPrice = watch(minPriceRef);
final maxPrice = watch(maxPriceRef);
return products
.where((p) => p.price >= minPrice && p.price <= maxPrice)
.toList();
});
Like StateRef
you wan watch a Computed
in the build method of a widget:
@override
Widget build(BuildContext context) {
final filteredProducts = context.watch(filteredProductsRef);
...
// Do something with `filteredProducts`.
}
Note: The whole code for the above snippets is available in the example file.
You may want to observe when the state changed and do some action accordingly (for example, logging state changes). To do so, you’ll need to implement the StateObserver
interface (or use a DelegatingStateObserver
) and provide an instance to the observers
parameter of the BinderScope
constructor.
bool onStateUpdated<T>(StateRef<T> ref, T oldState, T newState, Object action) {
logs.add(
'[${ref.key.name}#$action] changed from $oldState to $newState',
);
// Indicates whether this observer handled the changes.
// If true, then other observers are not called.
return true;
}
...
BinderScope(
observers: [DelegatingStateObserver(onStateUpdated)],
child: const SubTree(),
);
Binder comes with a built-in way to move in the timeline of the state changes. To be able to undo/redo a state change, you must add a MementoScope
in your tree. The MementoScope
will be able to observe all changes made below it:
return MementoScope(
child: Builder(builder: (context) {
return MaterialApp(
home: const MyHomePage(),
);
}),
);
Then, in a business logic, stored below the MementoScope
, you will be able to call undo
/redo
methods.
Note: You will get an AssertionError at runtime if you don’t provide a MementoScope
above the business logic calling undo
/redo
.
In some situation, you’ll want to do some action before the BinderScope
hosting a business logic component, is disposed. To have the chance to do this, your logic will need to implement the Disposable
interface.
class MyLogic with Logic implements Disposable {
void dispose(){
// Do some stuff before this logic go away.
}
}
If you want to navigate to another screen or show a dialog when a state change, you can use the StateListener
widget.
For example, in an authentication view, you may want to show an alert dialog when the authentication failed. To do it, in the logic component you could set a state indicating whether the authentication succeeded or not, and have a StateListener
in your view do respond to these state changes:
return StateListener(
watchable: authenticationResultRef,
onStateChanged: (context, AuthenticationResult state) {
if (state is AuthenticationFailure) {
showDialog<void>(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Error'),
content: const Text('Authentication failed'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Ok'),
),
],
);
},
);
} else {
Navigator.of(context).pushReplacementNamed(route_names.home);
}
},
child: child,
);
In the above snippet, each time the state referenced by authenticationResultRef
changes, the onStateChanged
callback is fired. In this callback we simply verify the type of the state to determine whether we have to show an alert dialog or not.
Binder wants to simplify the debugging of your app. By using the DartDev tools, you will be able to inspect the current states hosted by any BinderScope
.
You can find code snippets for vscode at snippets.
I’m working on my packages on my free-time, but I don’t have as much time as I would. If this package or any other package I created is helping you, please consider to sponsor me so that I can take time to read the issues, fix bugs, merge pull requests and add features to these packages.
Feel free to contribute to this project.
If you find a bug or want a feature, but don’t know how to fix/implement it, please fill an issue.
If you fixed a bug or implemented a feature, please send a pull request.
Author: letsar
Source Code: https://github.com/letsar/binder
#flutter #dart #mobile-apps
1595491178
The electric scooter revolution has caught on super-fast taking many cities across the globe by storm. eScooters, a renovated version of old-school scooters now turned into electric vehicles are an environmentally friendly solution to current on-demand commute problems. They work on engines, like cars, enabling short traveling distances without hassle. The result is that these groundbreaking electric machines can now provide faster transport for less — cheaper than Uber and faster than Metro.
Since they are durable, fast, easy to operate and maintain, and are more convenient to park compared to four-wheelers, the eScooters trend has and continues to spike interest as a promising growth area. Several companies and universities are increasingly setting up shop to provide eScooter services realizing a would-be profitable business model and a ready customer base that is university students or residents in need of faster and cheap travel going about their business in school, town, and other surrounding areas.
In many countries including the U.S., Canada, Mexico, U.K., Germany, France, China, Japan, India, Brazil and Mexico and more, a growing number of eScooter users both locals and tourists can now be seen effortlessly passing lines of drivers stuck in the endless and unmoving traffic.
A recent report by McKinsey revealed that the E-Scooter industry will be worth― $200 billion to $300 billion in the United States, $100 billion to $150 billion in Europe, and $30 billion to $50 billion in China in 2030. The e-Scooter revenue model will also spike and is projected to rise by more than 20% amounting to approximately $5 billion.
And, with a necessity to move people away from high carbon prints, traffic and congestion issues brought about by car-centric transport systems in cities, more and more city planners are developing more bike/scooter lanes and adopting zero-emission plans. This is the force behind the booming electric scooter market and the numbers will only go higher and higher.
Companies that have taken advantage of the growing eScooter trend develop an appthat allows them to provide efficient eScooter services. Such an app enables them to be able to locate bike pick-up and drop points through fully integrated google maps.
It’s clear that e scooters will increasingly become more common and the e-scooter business model will continue to grab the attention of manufacturers, investors, entrepreneurs. All this should go ahead with a quest to know what are some of the best electric bikes in the market especially for anyone who would want to get started in the electric bikes/scooters rental business.
We have done a comprehensive list of the best electric bikes! Each bike has been reviewed in depth and includes a full list of specs and a photo.
https://www.kickstarter.com/projects/enkicycles/billy-were-redefining-joyrides
To start us off is the Billy eBike, a powerful go-anywhere urban electric bike that’s specially designed to offer an exciting ride like no other whether you want to ride to the grocery store, cafe, work or school. The Billy eBike comes in 4 color options – Billy Blue, Polished aluminium, Artic white, and Stealth black.
Price: $2490
Available countries
Available in the USA, Europe, Asia, South Africa and Australia.This item ships from the USA. Buyers are therefore responsible for any taxes and/or customs duties incurred once it arrives in your country.
Features
Specifications
Why Should You Buy This?
**Who Should Ride Billy? **
Both new and experienced riders
**Where to Buy? **Local distributors or ships from the USA.
Featuring a sleek and lightweight aluminum frame design, the 200-Series ebike takes your riding experience to greater heights. Available in both black and white this ebike comes with a connected app, which allows you to plan activities, map distances and routes while also allowing connections with fellow riders.
Price: $2099.00
Available countries
The Genze 200 series e-Bike is available at GenZe retail locations across the U.S or online via GenZe.com website. Customers from outside the US can ship the product while incurring the relevant charges.
Features
Specifications
https://ebikestore.com/shop/norco-vlt-s2/
The Norco VLT S2 is a front suspension e-Bike with solid components alongside the reliable Bosch Performance Line Power systems that offer precise pedal assistance during any riding situation.
Price: $2,699.00
Available countries
This item is available via the various Norco bikes international distributors.
Features
Specifications
http://www.bodoevs.com/bodoev/products_show.asp?product_id=13
Manufactured by Bodo Vehicle Group Limited, the Bodo EV is specially designed for strong power and extraordinary long service to facilitate super amazing rides. The Bodo Vehicle Company is a striking top in electric vehicles brand field in China and across the globe. Their Bodo EV will no doubt provide your riders with high-level riding satisfaction owing to its high-quality design, strength, breaking stability and speed.
Price: $799
Available countries
This item ships from China with buyers bearing the shipping costs and other variables prior to delivery.
Features
Specifications
#android app #autorent #entrepreneurship #ios app #minimum viable product (mvp) #mobile app development #news #app like bird #app like bounce #app like lime #autorent #best electric bikes 2020 #best electric bikes for rental business #best electric kick scooters 2020 #best electric kickscooters for rental business #best electric scooters 2020 #best electric scooters for rental business #bird scooter business model #bird scooter rental #bird scooter rental cost #bird scooter rental price #clone app like bird #clone app like bounce #clone app like lime #electric rental scooters #electric scooter company #electric scooter rental business #how do you start a moped #how to start a moped #how to start a scooter rental business #how to start an electric company #how to start electric scooterrental business #lime scooter business model #scooter franchise #scooter rental business #scooter rental business for sale #scooter rental business insurance #scooters franchise cost #white label app like bird #white label app like bounce #white label app like lime
1595494844
Are you leading an organization that has a large campus, e.g., a large university? You are probably thinking of introducing an electric scooter/bicycle fleet on the campus, and why wouldn’t you?
Introducing micro-mobility in your campus with the help of such a fleet would help the people on the campus significantly. People would save money since they don’t need to use a car for a short distance. Your campus will see a drastic reduction in congestion, moreover, its carbon footprint will reduce.
Micro-mobility is relatively new though and you would need help. You would need to select an appropriate fleet of vehicles. The people on your campus would need to find electric scooters or electric bikes for commuting, and you need to provide a solution for this.
To be more specific, you need a short-term electric bike rental app. With such an app, you will be able to easily offer micro-mobility to the people on the campus. We at Devathon have built Autorent exactly for this.
What does Autorent do and how can it help you? How does it enable you to introduce micro-mobility on your campus? We explain these in this article, however, we will touch upon a few basics first.
You are probably thinking about micro-mobility relatively recently, aren’t you? A few relevant insights about it could help you to better appreciate its importance.
Micro-mobility is a new trend in transportation, and it uses vehicles that are considerably smaller than cars. Electric scooters (e-scooters) and electric bikes (e-bikes) are the most popular forms of micro-mobility, however, there are also e-unicycles and e-skateboards.
You might have already seen e-scooters, which are kick scooters that come with a motor. Thanks to its motor, an e-scooter can achieve a speed of up to 20 km/h. On the other hand, e-bikes are popular in China and Japan, and they come with a motor, and you can reach a speed of 40 km/h.
You obviously can’t use these vehicles for very long commutes, however, what if you need to travel a short distance? Even if you have a reasonable public transport facility in the city, it might not cover the route you need to take. Take the example of a large university campus. Such a campus is often at a considerable distance from the central business district of the city where it’s located. While public transport facilities may serve the central business district, they wouldn’t serve this large campus. Currently, many people drive their cars even for short distances.
As you know, that brings its own set of challenges. Vehicular traffic adds significantly to pollution, moreover, finding a parking spot can be hard in crowded urban districts.
Well, you can reduce your carbon footprint if you use an electric car. However, electric cars are still new, and many countries are still building the necessary infrastructure for them. Your large campus might not have the necessary infrastructure for them either. Presently, electric cars don’t represent a viable option in most geographies.
As a result, you need to buy and maintain a car even if your commute is short. In addition to dealing with parking problems, you need to spend significantly on your car.
All of these factors have combined to make people sit up and think seriously about cars. Many people are now seriously considering whether a car is really the best option even if they have to commute only a short distance.
This is where micro-mobility enters the picture. When you commute a short distance regularly, e-scooters or e-bikes are viable options. You limit your carbon footprints and you cut costs!
Businesses have seen this shift in thinking, and e-scooter companies like Lime and Bird have entered this field in a big way. They let you rent e-scooters by the minute. On the other hand, start-ups like Jump and Lyft have entered the e-bike market.
Think of your campus now! The people there might need to travel short distances within the campus, and e-scooters can really help them.
What advantages can you get from micro-mobility? Let’s take a deeper look into this question.
Micro-mobility can offer several advantages to the people on your campus, e.g.:
#android app #autorent #ios app #mobile app development #app like bird #app like bounce #app like lime #autorent #bird scooter business model #bird scooter rental #bird scooter rental cost #bird scooter rental price #clone app like bird #clone app like bounce #clone app like lime #electric rental scooters #electric scooter company #electric scooter rental business #how do you start a moped #how to start a moped #how to start a scooter rental business #how to start an electric company #how to start electric scooterrental business #lime scooter business model #scooter franchise #scooter rental business #scooter rental business for sale #scooter rental business insurance #scooters franchise cost #white label app like bird #white label app like bounce #white label app like lime
1624524513
Microsoft power bi(business intelligence) helps organizations in analyzing data and also share insights. Using power bi service, small and big enterprises can monitor their business operations closely and receive quick answers via rich dashboards. This technology keeps updating itself every month with amazing features and functions.
As per Markets and Markets report, the global BI market size to grow from USD 23.1 billion in 2020 to USD 33.3 billion by the year 2025 @CAGR of 7.6% according to the forecast period.
Rising demand for data visualization, digital transformation success, increase in cloud adoption, and rising investment in analytics has led many companies to make a shift to this technology. But, due to the presence of a number of power bi consulting companies, it would be hard to decide on one.
To ease this, I have researched on top 10 power bi consultants and checked on major pointers personally.
Here I have listed the top 10 power bi consultants(having 100% global recognition) on the basis of some important parameters’ viz. Expertise level, hourly price, client feedback, the latest technologies used, workfolio, etc.
Find the list below:
Visit Website - https://www.valuecoders.com/blog/technology-and-apps/top-power-bi-development-companies-to-grow-your-business-in-the-modern-era/
#power bi consultant #power bi consultants #power bi consulting #power bi consulting services #power bi development #microsoft power bi developer
1604008260
A lightweight, yet powerful way to bind your application state with your business logic.
As other state management pattern, binder aims to separate the application state from the business logic that updates it:
We can see the whole application state as the agglomeration of a multitude of tiny states. Each state being independent from each other. A view can be interested in some particular states and has to use a logic component to update them.
In the pubspec.yaml
of your flutter project, add the following dependency:
dependencies:
binder: <latest_version>
In your library add the following import:
import 'package:binder/binder.dart';
Any state has to be declared through a StateRef
with its initial value:
final counterRef = StateRef(0);
Note: A state should be immutable, so that the only way to update it, is through methods provided by this package.
Any logic component has to be declared through a LogicRef
with a function that will be used to create it:
final counterViewLogicRef = LogicRef((scope) => CounterViewLogic(scope));
The scope
argument can then be used by the logic to mutate the state and access other logic components.
Note: You can declare StateRef
and LogicRef
objects as public global variables if you want them to be accessible from other parts of your app.
If we want our CounterViewLogic
to be able to increment our counter state, we might write something like this:
/// A business logic component can apply the [Logic] mixin to have access to
/// useful methods, such as `write` and `read`.
class CounterViewLogic with Logic {
const CounterViewLogic(this.scope);
/// This is the object which is able to interact with other components.
@override
final Scope scope;
/// We can use the [write] method to mutate the state referenced by a
/// [StateRef] and [read] to obtain its current state.
void increment() => write(counterRef, read(counterRef) + 1);
}
In order to bind all of this together in a Flutter app, we have to use a dedicated widget called BinderScope
. This widget is responsible for holding a part of the application state and for providing the logic components. You will typically create this widget above the MaterialApp
widget:
BinderScope(
child: MaterialApp(
home: CounterView(),
),
);
In any widget under the BinderScope
, you can call extension methods on BuildContext
to bind the view to the application state and to the business logic components:
class CounterView extends StatelessWidget {
const CounterView({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
/// We call the [watch] extension method on a [StateRef] to rebuild the
/// widget when the underlaying state changes.
final counter = context.watch(counterRef);
return Scaffold(
appBar: AppBar(title: const Text('Binder example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
Text('$counter', style: Theme.of(context).textTheme.headline4),
],
),
),
floatingActionButton: FloatingActionButton(
/// We call the [use] extension method to get a business logic component
/// and call the appropriate method.
onPressed: () => context.use(counterViewLogicRef).increment(),
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
This is all you need to know for a basic usage.
Note: The whole code for the above snippets is available in the example file.
A state can be of a simple type as an int
or a String
but it can also be more complex, such as the following:
class User {
const User(this.firstName, this.lastName, this.score);
final String firstName;
final String lastName;
final int score;
}
Some views of an application are only interested in some parts of the global state. In these cases, it can be more efficient to select only the part of the state that is useful for these views.
For example, if we have an app bar title which is only responsible for displaying the full name of a User
, and we don’t want it to rebuild every time the score changes, we will use the select
method of the StateRef
to watch only a sub part of the state:
class AppBarTitle extends StatelessWidget {
const AppBarTitle({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
final fullName = context.watch(
userRef.select((user) => '${user.firstName} ${user.lastName}'),
);
return Text(fullName);
}
}
It can be useful to be able to override the initial state of StateRef
or the factory of LogicRef
in some conditions:
Let’s say we want to create an app where a user can create counters and see the sum of all counters:
We could do this by having a global state being a list of integers, and a business logic component for adding counters and increment them:
final countersRef = StateRef(const <int>[]);
final countersLogic = LogicRef((scope) => CountersLogic(scope));
class CountersLogic with Logic {
const CountersLogic(this.scope);
@override
final Scope scope;
void addCounter() {
write(countersRef, read(countersRef).toList()..add(0));
}
void increment(int index) {
final counters = read(countersRef).toList();
counters[index]++;
write(countersRef, counters);
}
}
We can then use the select
extension method in a widget to watch the sum of this list:
final sum = context.watch(countersRef.select(
(counters) => counters.fold<int>(0, (a, b) => a + b),
));
Now, for creating the counter view, we can have an index
parameter in the constructor of this view. This has some drawbacks:
index
for every widget down the tree, up to our child.const
keyword anymore.A better approach would be to create a BinderScope
above each counter widget. We would then configure this BinderScope
to override the state of a StateRef
for its descendants, with a different initial value.
Any StateRef
or LogicRef
can be overriden in a BinderScope
. When looking for the current state, a descendant will get the state of the first reference overriden in a BinderScope
until the root BinderScope
. This can be written like this:
final indexRef = StateRef(0);
class HomeView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final countersCount =
context.watch(countersRef.select((counters) => counters.length));
return Scaffold(
...
child: GridView(
...
children: [
for (int i = 0; i < countersCount; i++)
BinderScope(
overrides: [indexRef.overrideWith(i)],
child: const CounterView(),
),
],
),
...
);
}
}
The BinderScope
constructor has an overrides
parameter which can be supplied from an overrideWith
method on StateRef
and LogicRef
instances.
Note: The whole code for the above snippets is available in the example file.
Let’s say you have an api client in your app:
final apiClientRef = LogicRef((scope) => ApiClient());
If you want to provide a mock instead, while testing, you can do:
testWidgets('Test your view by mocking the api client', (tester) async {
final mockApiClient = MockApiClient();
// Build our app and trigger a frame.
await tester.pumpWidget(
BinderScope(
overrides: [apiClientRef.overrideWith((scope) => mockApiClient)],
child: const MyApp(),
),
);
expect(...);
});
Whenever the apiClientRef
is used in your app, the MockApiClient
instance will be used instead of the real one.
You may encounter a situation where different widgets are interested in a derived state which is computed from different sates. In this situation it can be helpful to have a way to define this derived state globally, so that you don’t have to copy/paste this logic across your widgets. Binder comes with a Computed
class to help you with that use case.
Let’s say you have a list of products referenced by productsRef
, each product has a price, and you can filter these products according to a price range (referenced by minPriceRef
and maxPriceRef
).
You could then define the following Computed
instance:
final filteredProductsRef = Computed((watch) {
final products = watch(productsRef);
final minPrice = watch(minPriceRef);
final maxPrice = watch(maxPriceRef);
return products
.where((p) => p.price >= minPrice && p.price <= maxPrice)
.toList();
});
Like StateRef
you wan watch a Computed
in the build method of a widget:
@override
Widget build(BuildContext context) {
final filteredProducts = context.watch(filteredProductsRef);
...
// Do something with `filteredProducts`.
}
Note: The whole code for the above snippets is available in the example file.
You may want to observe when the state changed and do some action accordingly (for example, logging state changes). To do so, you’ll need to implement the StateObserver
interface (or use a DelegatingStateObserver
) and provide an instance to the observers
parameter of the BinderScope
constructor.
bool onStateUpdated<T>(StateRef<T> ref, T oldState, T newState, Object action) {
logs.add(
'[${ref.key.name}#$action] changed from $oldState to $newState',
);
// Indicates whether this observer handled the changes.
// If true, then other observers are not called.
return true;
}
...
BinderScope(
observers: [DelegatingStateObserver(onStateUpdated)],
child: const SubTree(),
);
Binder comes with a built-in way to move in the timeline of the state changes. To be able to undo/redo a state change, you must add a MementoScope
in your tree. The MementoScope
will be able to observe all changes made below it:
return MementoScope(
child: Builder(builder: (context) {
return MaterialApp(
home: const MyHomePage(),
);
}),
);
Then, in a business logic, stored below the MementoScope
, you will be able to call undo
/redo
methods.
Note: You will get an AssertionError at runtime if you don’t provide a MementoScope
above the business logic calling undo
/redo
.
In some situation, you’ll want to do some action before the BinderScope
hosting a business logic component, is disposed. To have the chance to do this, your logic will need to implement the Disposable
interface.
class MyLogic with Logic implements Disposable {
void dispose(){
// Do some stuff before this logic go away.
}
}
If you want to navigate to another screen or show a dialog when a state change, you can use the StateListener
widget.
For example, in an authentication view, you may want to show an alert dialog when the authentication failed. To do it, in the logic component you could set a state indicating whether the authentication succeeded or not, and have a StateListener
in your view do respond to these state changes:
return StateListener(
watchable: authenticationResultRef,
onStateChanged: (context, AuthenticationResult state) {
if (state is AuthenticationFailure) {
showDialog<void>(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Error'),
content: const Text('Authentication failed'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Ok'),
),
],
);
},
);
} else {
Navigator.of(context).pushReplacementNamed(route_names.home);
}
},
child: child,
);
In the above snippet, each time the state referenced by authenticationResultRef
changes, the onStateChanged
callback is fired. In this callback we simply verify the type of the state to determine whether we have to show an alert dialog or not.
Binder wants to simplify the debugging of your app. By using the DartDev tools, you will be able to inspect the current states hosted by any BinderScope
.
You can find code snippets for vscode at snippets.
I’m working on my packages on my free-time, but I don’t have as much time as I would. If this package or any other package I created is helping you, please consider to sponsor me so that I can take time to read the issues, fix bugs, merge pull requests and add features to these packages.
Feel free to contribute to this project.
If you find a bug or want a feature, but don’t know how to fix/implement it, please fill an issue.
If you fixed a bug or implemented a feature, please send a pull request.
Author: letsar
Source Code: https://github.com/letsar/binder
#flutter #dart #mobile-apps
1620885491
Hire top dedicated Mirosoft power BI consultants from ValueCoders who aim at leveraging their potential to address organizational challenges for large-scale data storage and seamless processing.
We have a team of dedicated power BI consultants who help start-ups, SMEs, and enterprises to analyse business data and get useful insights.
What are you waiting for? Contact us now!
No Freelancers, 100% Own Staff
Experienced Consultants
Continuous Monitoring
Lean Processes, Agile Mindset
Non-Disclosure Agreement
Up To 2X Less Time
##power bi service #power bi consultant #power bi consultants #power bi consulting #power bi developer #power bi development