Flutter equatable

Flutter equatable DEFAULT

using Equatable class with flutter_bloc

We are using the Equatable package so that we can compare instances of classes without having to manually override "==" and hashCode.

Equatable class allows us to compare two object for equality.

This is the equatable example. Let's say we have the following class:

We can create instances of Person like so:

Later if we try to compare two instances of Person either in our production code or in our tests we will run into a problem.

In order to be able to compare two instances of Person we need to change our class to override == and hashCode like so:

Now if we run the following code again:

it will be able to compare different instances of Person.

So you don't have to waste your time writing lots of boilerplate code when overrides "==" and hashCode.

Use Equatable like

In bloc case; if you try to use bloc with mutable state you will face with problems without Equatable. It makes resources immutable reduce performance. It’s more expensive to create copies than to mutate a property.

If it is not clear to you that I tried to explain, reading this could help you.

Sours: https://stackoverflow.com/questions/64316700/using-equatable-class-with-flutter-bloc

Flutter Tutorial - Compare Objects - Equatable VS Hashcode & Equals

Google's Flutter 1.20 stable announced with new features - Navoki

Flutter Google cross-platform UI framework has released a new version 1.20 stable.

Flutter is Google’s UI framework to make apps for Android, iOS, Web, Windows, Mac, Linux, and Fuchsia OS. Since the last 2 years, the flutter Framework has already achieved popularity among mobile developers to develop Android and iOS apps. In the last few releases, Flutter also added the support of making web applications and desktop applications.

Last month they introduced the support of the Linux desktop app that can be distributed through Canonical Snap Store(Snapcraft), this enables the developers to publish there Linux desktop app for their users and publish on Snap Store.  If you want to learn how to Publish Flutter Desktop app in Snap Store that here is the tutorial.

Flutter 1.20 Framework is built on Google’s made Dart programming language that is a cross-platform language providing native performance, new UI widgets, and other more features for the developer usage.

Here are the few key points of this release:

Performance improvements for Flutter and Dart

In this release, they have got multiple performance improvements in the Dart language itself. A new improvement is to reduce the app size in the release versions of the app. Another performance improvement is to reduce junk in the display of app animation by using the warm-up phase.


If your app is junk information during the first run then the Skia Shading Language shader provides for pre-compilation as part of your app’s build. This can speed it up by more than 2x.

Added a better support of mouse cursors for web and desktop flutter app,. Now many widgets will show cursor on top of them or you can specify the type of supported cursor you want.

Autofill for mobile text fields

Autofill was already supported in native applications now its been added to the Flutter SDK. Now prefilled information stored by your OS can be used for autofill in the application. This feature will be available soon on the flutter web.


A new widget for interaction

 is a new widget design for common interactions in your app like pan, zoom drag and drop for resizing the widget. Informations on this you can check more on this API documentation where you can try this widget on the DartPad. In this release, drag-drop has more features added like you can know precisely where the drop happened and get the position.

Updated Material Slider, RangeSlider, TimePicker, and DatePicker

In this new release, there are many pre-existing widgets that were updated to match the latest material guidelines, these updates include better interaction with  and ,  with support for date range and time picker with the new style.


New  format

Other than these widget updates there is some update within the project also like in  file format. If you are a flutter plugin publisher then your old   is no longer supported to publish a plugin as the older format does not specify for which platform plugin you are making. All existing plugin will continue to work with flutter apps but you should make a plugin update as soon as possible.

Preview of embedded Dart DevTools in Visual Studio Code

Visual Studio code flutter extension got an update in this release. You get a preview of new features where you can analyze that Dev tools in your coding workspace. Enable this feature in your vs code by setting. Dart DevTools menu you can choose your favorite page embed on your code workspace.

Network tracking

The updated the Dev tools comes with the network page that enables network profiling. You can track the timings and other information like status and content type of your** network calls** within your app. You can also monitor gRPC traffic.

Generate type-safe platform channels for platform interop

Pigeon is a command-line tool that will generate types of safe platform channels without adding additional dependencies. With this instead of manually matching method strings on platform channel and serializing arguments, you can invoke native class and pass nonprimitive data objects by directly calling the method.

There is still a long list of updates in the new version of Flutter 1.2 that we cannot cover in this blog. You can get more details you can visit the official site to know more. Also, you can subscribe to the Navoki newsletter to get updates on these features and upcoming new updates and lessons. In upcoming new versions, we might see more new features and improvements.

You can get more free Flutter tutorials you can follow these courses:

#dart #developers #flutter #app developed #dart devtools in visual studio code #firebase local emulator suite in flutter #flutter autofill #flutter date picker #flutter desktop linux app build and publish on snapcraft store #flutter pigeon #flutter range slider #flutter slider #flutter time picker #flutter tutorial #flutter widget #google flutter #linux #navoki #pubspec format #setup flutter desktop on windows

Sours: https://morioh.com/p/14c4e4ec3121
  1. Chainsaw lowes
  2. Weht 25 live stream
  3. Zillow mexico maine
  4. Pratyusha banerjee death photos
  5. Mac allister parts

There are numerous documentations on the web explaining the purpose of the BLoC pattern and how it’s applied to minimal examples. This tutorial aims for the migration of an existing app to this state management architecture.

For that, we use the calculator app whose creation was explained in another tutorial. The whole app’s state is managed by a StatefulWidget. Let’s tweak it to let the entire state be managed by a BLoC which will lead to a separation of the UI from the business logic.


Why do we want such a migration in the first place? As long as everything works, we can keep it that way, can’t we?

Yes and no. Of course the current implementation works. However, if we were to change anything, we were unable to say with certainty that the functionality would not break.

This problem is nothing new. That’s why people invented software testing. But now we come to the core question: is this implementation even testable? What would our unit-tests look like if we wanted to ensure the current implementation?

The answer is: it’s not. Our widget has two responsibilities: displaying the UI and defining the business logic. Changing parts of the UI could possibly break the business logic because it’s not strictly separated. Same applies the other way around.

Uncle Bob‘s opinion on that: a responsibility is defined as a reason to change. Every class or module should have exactly one reason to be changed.


Implementing the BLoC pattern involves a lot of boilerplate code (Bloc, Event, State and all of its abstract logic). That’s why we make it easy for us and use a prefabricated solution: the bloc library. The package contains several classes that prevents us from implementing the pattern ourselves.

Let’s add the dependency to the project:

dependencies: flutter: sdk: flutter flutter_bloc: ^6.0.3 equatable: ^1.2.5


Let’s start with the events. That’s quite easy because a glimpse at the UI can pretty quickly make us realize which events we need:

Flutter calculator keypad complete

There are four types of buttons the user can press resulting in four distinct interactions:

  • Pressing a number button (0-9)
  • Pressing an operator button (+, -, x, /)
  • Pressing the result calculation button (=)
  • Pressing the “clear” button (c)
Flutter BLoC pattern event overview

Let’s translate these formal requirements into events in the BLoC context:

import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; abstract class CalculationEvent extends Equatable { const CalculationEvent(); } class NumberPressed extends CalculationEvent { final int number; const NumberPressed({@required this.number}) : assert(number != null); @override List<Object> get props => [number]; } class OperatorPressed extends CalculationEvent { final String operator; const OperatorPressed({@required this.operator}) : assert(operator != null); @override List<Object> get props => [operator]; } class CalculateResult extends CalculationEvent { @override List<Object> get props => []; } class ClearCalculation extends CalculationEvent { @override List<Object> get props => []; }

The only events that require a parameter are and (because we need to distinguish which one was taken). The two other events don’t have any properties.


The states are fairly easy. That’s because our UI does not care about what exactly happened. It only cares about the situation when the whole calculation (consisting of two operands, an operator and a result) changes. That’s why we only need one actual state saying that the calculation has changed. Additionally we need one initial state. Since we don’t have any asynchronous operations, we don’t need a “loading” state either.

import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; import '../calculation_model.dart'; abstract class CalculationState extends Equatable { final CalculationModel calculationModel; const CalculationState({@required this.calculationModel}) : assert(calculationModel != null); @override List<Object> get props => [calculationModel]; } class CalculationInitial extends CalculationState { CalculationInitial() : super(calculationModel: CalculationModel()); } class CalculationChanged extends CalculationState { final CalculationModel calculationModel; const CalculationChanged({@required this.calculationModel}) : assert(calculationModel != null), super(calculationModel: calculationModel); @override List<Object> get props => [calculationModel]; }

Instead of duplicating every property in both of the states, we use a separate class called . This way, if we change something (e.g. displaying the last result as well), we only need to change one model. This is what the model looks like:

import 'package:equatable/equatable.dart'; class CalculationModel extends Equatable { CalculationModel({ this.firstOperand, this.operator, this.secondOperand, this.result, }); final int firstOperand; final String operator; final int secondOperand; final int result; @override String toString() { return "$firstOperand$operator$secondOperand=$result"; } @override List<Object> get props => [firstOperand, operator, secondOperand, result]; }

It’s important to let this model extend . Same goes for the states. This is because we need the UI to change only when something has actually changed. We need to define how Dart decides whether there was a change. This is done by defining .


class CalculationBloc extends Bloc<CalculationEvent, CalculationState> { CalculationBloc() : super(CalculationInitial()); @override Stream<CalculationState> mapEventToState( CalculationEvent event, ) async* { if (event is ClearCalculation) { yield CalculationInitial(); } } }

There is only one method we need to override: . This method is responsible for handling incoming events and emitting the new state. We start with the simplest one: . This makes it emit the initial state again ().

Next one: event.

Future<CalculationState> _mapOperatorPressedToState( OperatorPressed event, ) async { List<String> allowedOperators = ['+', '-', '*', '/']; if (!allowedOperators.contains(event.operator)) { return state; } CalculationModel model = state.calculationModel; return CalculationChanged( calculationModel: CalculationModel( firstOperand: model.firstOperand == null ? 0 : model.firstOperand, operator: event.operator, secondOperand: model.secondOperand, result: model.result ) ); }

We notice something: it’s crucial that we use a new instance of the model. If we work with the reference, the bloc library will have problems checking the equality and thus might fail to let the UI know about the update. However, we need to let the new instance have the old values so that we don’t lose state when we emit a new .

This seems like a lot of boilerplate code if we have a method that handles several cases with several states as outcome. That’s why we enhance the by a method called :

CalculationModel copyWith({ int Function() firstOperand, String Function() operator, int Function() secondOperand, int Function() result }) { return CalculationModel( firstOperand: firstOperand?.call() ?? this.firstOperand, operator: operator?.call() ?? this.operator, secondOperand: secondOperand?.call() ?? this.secondOperand, result: result?.call() ?? this.result, ); }

You might ask yourself why we expect functions and not the date types itself. It’s because otherwise null values are treated exactly as not given parameters. I will explain in another article in more detail.

Now we can write the very same method like this:

Future<CalculationState> _mapOperatorPressedToState( OperatorPressed event, ) async { List<String> allowedOperators = ['+', '-', '*', '/']; if (!allowedOperators.contains(event.operator)) { return state; } CalculationModel model = state.calculationModel; CalculationModel newModel = state.calculationModel.copyWith( firstOperand: () => model.firstOperand == null ? 0 : model.firstOperand, operator: () => event.operator ); return CalculationChanged(calculationModel: newModel); }

Let’s continue with the handling of the event:

Future<CalculationState> _mapCalculateResultToState( CalculateResult event, ) async { CalculationModel model = state.calculationModel; if (model.operator == null || model.secondOperand == null) { return state; } int result = 0; switch (model.operator) { case '+': result = model.firstOperand + model.secondOperand; break; case '-': result = model.firstOperand - model.secondOperand; break; case '*': result = model.firstOperand * model.secondOperand; break; case '/': if (model.secondOperand == 0) { CalculationModel resultModel = CalculationInitial().calculationModel.copyWith( firstOperand: () => 0 ); return CalculationChanged(calculationModel: resultModel); } result = model.firstOperand ~/ model.secondOperand; break; }

We just apply the logic, we had before the transformation. Notable here is that a division by zero results in “0” as the first operand for the next calculation.

Now, the biggest event is because depending on the state of calculation we’re currently in, pressing a number can have different effects. That’s why the handling is a little bit more complex here:

Future<CalculationState> _mapNumberPressedToState( NumberPressed event, ) async { CalculationModel model = state.calculationModel; if (model.result != null) { CalculationModel newModel = model.copyWith( firstOperand: () => event.number, result: () => null ); return CalculationChanged(calculationModel: newModel); } if (model.firstOperand == null) { CalculationModel newModel = model.copyWith( firstOperand: () => event.number ); return CalculationChanged(calculationModel: newModel); } if (model.operator == null) { CalculationModel newModel = model.copyWith( firstOperand: () => int.parse('${model.firstOperand}${event.number}') ); return CalculationChanged(calculationModel: newModel); } if (model.secondOperand == null) { CalculationModel newModel = model.copyWith( secondOperand: () => event.number ); return CalculationChanged(calculationModel: newModel); } return CalculationChanged( calculationModel: model.copyWith( secondOperand: () => int.parse('${model.secondOperand}${event.number}') ) ); }

But again, we’re just copying off the former behavior from the version of the app without BLoC pattern.

Last thing to do is letting the widget emit the events and react on the emitted states of the BLoC.

@override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter basic calculator', home: Scaffold( body: BlocProvider( create: (context) { return CalculationBloc(); }, child: Calculation(), ), ), ); }

First off, in the , we need to add a . This is necessary to enable our widget to communicate with the BLoC.

Now, instead of calling whenever we recognize an interaction with the UI, we emit an event:

numberPressed(int number) { context.bloc<CalculationBloc>().add(NumberPressed(number: number)); } operatorPressed(String operator) { context.bloc<CalculationBloc>().add(OperatorPressed(operator: operator)); } calculateResult() { context.bloc<CalculationBloc>().add(CalculateResult()); } clear() { context.bloc<CalculationBloc>().add(ClearCalculation()); }

Now, if we want the UI to display the result accordingly, we need to wrap the with a this gives us the ability to react on an emitted state.

BlocBuilder<CalculationBloc, CalculationState>( builder: (context, CalculationState state) { return ResultDisplay( text: _getDisplayText(state.calculationModel), ); }, ), ... String _getDisplayText(CalculationModel model) { if (model.result != null) { return '${model.result}'; } if (model.secondOperand != null) { return '${model.firstOperand}${model.operator}${model.secondOperand}'; } if (model.operator != null) { return '${model.firstOperand}${model.operator}'; } if (model.firstOperand != null) { return '${model.firstOperand}'; } return "${model.result ?? 0}"; }

Final words

The BLoC pattern is fantastic way of separating UI concerns from business logic concerns. Also, it enables the developer to manage state leaving the widget only as a reactive presentation layer. It might be a little bit confusing at first, but once you get the fundamental thoughts, it is not so hard to apply this pattern. I hope this little example cleared it up a little bit.

If you want the full source, there is the repository before (current master) and after the BLoC PR:

Categories TutorialsTags Architecture, BLoC, Dart 2.10.0, Flutter 1.21.0, State ManagementSours: https://www.flutterclutter.dev/flutter/tutorials/applying-the-bloc-pattern-in-practice/2020/1732/
Flutter - Уровень домена: Entity и Equatable

Simplify Equality Comparisons

Build StatusCode CoveragePub Package
Star on GitHubstyle: effective dartDiscordMIT License

Being able to compare objects in often involves having to override the operator as well as .

Not only is it verbose and tedious, but failure to do so can lead to inefficient code which does not behave as we expect.

By default, returns true if two objects are the same instance.

Let's say we have the following class:

We can create create instances of like so:

Later if we try to compare two instances of either in our production code or in our tests we will run into a problem.

For more information about this, you can check out the official Dart Documentation.

In order to be able to compare two instances of we need to change our class to override and like so:

Now if we run the following code again:

it will be able to compare different instances of .

You can see how this can quickly become a hassle when dealing with complex classes. This is where comes in!

overrides and for you so you don't have to waste your time writing lots of boilerplate code.

There are other packages that will actually generate the boilerplate for you; however, you still have to run the code generation step which is not ideal.

With there is no code generation needed and we can focus more on writing amazing applications and less on mundane tasks.

First, we need to do add to the dependencies of the

Next, we need to install it:

Lastly, we need to extend

When working with json:

We can now compare instances of just like before without the pain of having to write all of that boilerplate. Note: Equatable is designed to only work with immutable objects so all member variables must be final (This is not just a feature of - overriding a with a mutable value can break hash-based collections).

Equatable also supports constructors:

Equatable can implement method including all the given props. If you want that behaviour for a specific object, just include the following:

For instance:

For the name , the output will be:

This flag by default is false and will return just the type:


can also be configured globally for all instances via

If is overridden for a specific class, then the value of is ignored. In other words, the local configuration always takes precedence over the global configuration.

Note: defaults to in debug mode and in release mode.

Sometimes it isn't possible to extend because your class already has a superclass. In this case, you can still get the benefits of by using the .

Let's say we want to make an class, we can use like so:

Now if we want to create a subclass of , we can just override .

You might be wondering what the performance impact will be if you use .

Equality Comparison A == A

ClassRuntime (μs)
Empty Equatable0.191
Hydrated Equatable0.190

Instantiation A()

ClassRuntime (μs)
Empty Equatable0.181
Hydrated Equatable0.182

*Performance Tests run using: Dart VM version: 2.4.0

Maintainers #

Sours: https://pub.dev/packages/equatable

Equatable flutter


🔥 Actualizando a bloc 4.0, flutter_bloc 4.0 y equatable 1.1 - El patrón BLoC en Flutter - Parte 5 🔥


Similar news:


2419 2420 2421 2422 2423