resocoder / flutter-tdd-clean-architecture-course Goto Github PK
View Code? Open in Web Editor NEWHome Page: https://resocoder.com/flutter-clean-architecture-tdd/
Home Page: https://resocoder.com/flutter-clean-architecture-tdd/
I read your article
Entity: The business objects of the application, they are the least likely to change when external things change
Model: Inherit and extend Domain layer Entity, realize json conversion and more needs
Generally speaking, business requirements have some additional fields, such as isSelected and isComplete, which are related to UI state
I don't know whether these attributes are placed in the Domain layer or in the Presentation layer to create a new model
I am very confused and hope to wait for your reply
Thanks
class QuestionEntitie {
final int id;
final String category;
final String question;
/// Should it be declared here?
final bool isSelected;
final bool isComplete;
}
class QuestionItem {
final QuestionEntitie item
/// or declare here ?
final bool isSelected;
final bool isComplete;
}
class QuestionModel extends QuestionEntitie {
QuestionModel({
required super.id,
required super.category,
required super.question,
});
factory QuestionModel.fromJson(Map<String, dynamic> json) {
return QuestionModel(
id: json['id'],
category: json['category'],
question: json['question'],
);
}
}
Hello everyone and @ResoDev ! The DataConnectionChecker is good lib, but it seems me it doesn't work in some countries, because I compiled app and it didn't work, than I debuged it and changed the line of coude if (await networkInfo.isConnected) to if(true) than it worked. Thats why I recomend everyone don't use DataConnectionChecker in future on your apps, becuase your app will not work in some countries, of course if it's need internet!
If I want to put the application on Android phone we need to add a permission for internet in the manifest like so:
<uses-permission android:name="android.permission.INTERNET" />
Btw, very thanks for all this stuff, video, tutorial and this code you rock ;) ! @ResoDev
It passed well with original
final tHasConnectionFuture = Future.value(true);
as well as with
final tHasConnectionFuture = Future.value(**false**);
How so?
Error: The superclass, 'Bloc<NumberTriviaEvent, NumberTriviaState>', has no unnamed
constructor that takes no arguments.
NumberTriviaBloc({
^^^^^^^^^^^^^^^^
Error: Compilation failed.
Does anybody else get it too ?
Hello, I am learning TDD with the course but I see that it is a little out of date, and now with Flutter 2.0 and null safety it would be a great idea to update it, because in addition to teaching TDD it would also help us with the issue of null safety in Flutter, which is so new
I have got many fails when testing usecases.
Because right now dart supports null safety
In my app, I have an authentication dataSource
designed to retrieve JWT access tokens and refresh tokens from my server. The access token has to be supplied on every call.
However, in my server calls, I may return a 401 and automatically use the refresh token to refresh the access token with a server call and then retry the original call.
When this happens, the contents of the access token will change. That could possible affect other things (like permissions, etc.). In addition, the new tokens will have to be saved to storage.
To do that, the authentication bloc
will have a new event of refreshed
and that might effect other things. The various other parts of the app can then reflect the new access token values.
So, do I create a singleton authentication bloc
and add
the refreshed
event to it when this happens from inside the API? That sounds right. That's the way I wrote it, but it doesn't seem "clean".
I have an AuthBloc on top of the tree. Beneath are ProfileBloc, PostBlocs...
When an event is launched to ProfileBloc/PostBlocs usecase called, repository. I get back from repository an 401 error, usecase returns Either as you used.
The problem is how do you think is the best way to "tell" this to AuthBloc (because it handles the authentication state)?
Any help with this so that still remains in a clean architecture way?
Hi and thank you so much for those tutorials, very interesting and well explained.
Can you please update your main.dart? i'm not sure how to initiate the app.
Thanks.
I am using equatable
as you describe in your course.
How do you manage when one class contains another and the contained class gets updated?
All the examples I find use a copyWith
approach with non-positional arguments.
Is this the best practices way to do it?
TIA
i'm trying running test with
flutter test
but it show error
test/features/number_trivia/data/models/number_trivia_model_test.dart:
fromJson should return a valid model when the JSON number is an integer [E]
FileSystemException: Cannot open file, path = 'test/fixtures/trivia.json'
(OS Error: No such file or directory, errno = 2)
dart:io File.readAsStringSync
fixtures/fixture_reader.dart 3:60 fixture
features/number_trivia/data/models/number_trivia_model_test.dart 26:25 main.<fn>.<fn>
Great course, thanks a lot.
How can I share an entity class between two features that use the same entity?
So, lo and behold because now I will introduce you to the Reso Coder's Flutter Clean Architecture Proposal - Explanation & Project Structure
I really cannot get this statement out of my head 😄and I propose to take this to the next level by:
repo make:entity EntityName
I'm coming from a backend background (Laravel) and really like the simple yet advanced tutorial you offer, and I can grantee that after a small increment changes, you may end with a solid framework that others can contribute on.
Thanks for your effort, it's my first time to be motivated to become a Mobile Developer!
I/flutter (30280): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (30280): The following assertion was thrown building Builder(dirty):
I/flutter (30280): You tried to access an instance of TriviaNumberLocalDataSource that was not ready yet
I/flutter (30280): 'package:get_it/get_it_impl.dart':
I/flutter (30280): Failed assertion: line 272 pos 14: 'instanceFactory.isReady'
I/flutter (30280): The relevant error-causing widget was:
I/flutter (30280): Builder
I/flutter (30280):
package:trivia_number_new/…/pages/trivia_number_page.dart:57
I/flutter (30280): When the exception was thrown, this was the stack
i got error
`fromJson should return a valid model when the JSON number is an integer:
ERROR: Expected: NumberTriviaModel:
Actual: NumberTriviaModel:
package:test_api expect
package:flutter_test/src/widget_tester.dart 431:3 expect
test\features\number_trivia\data\models\number_trivia_model_test.dart 30:9 main..`
how to Resolve this ?
Hey ResoCoder!
I am currently working on a flutter project, and have applied your architecture. It was hard in the beginning, but atm I have a pretty good understanding of it! I have one struggle though.
When working on the [feature]_bloc file, where everything comes together. I get an error when importing/injecting multiple usecases that there are multiple imports that have a "Params" class. VSCode suggests using prefixes to seperate them. I this the right solution or is there a better/less code solution?
this is my solution.
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:njoy_shopping_app/constants/error_constants.dart';
import 'package:njoy_shopping_app/core/error/failures.dart';
import 'package:njoy_shopping_app/features/merchants/data/models/merchant_model.dart';
import 'package:njoy_shopping_app/features/merchants/domain/usecases/get_merchant_by_id.dart'
as _merchantById;
import 'package:njoy_shopping_app/features/merchants/domain/usecases/get_merchants.dart'
as _merchants;
import 'package:njoy_shopping_app/features/merchants/domain/usecases/get_merchants_by_name.dart'
as _merchantByName;
import './bloc.dart';
import 'package:meta/meta.dart';
class MerchantBloc extends Bloc<MerchantEvent, MerchantState> {
final _merchantById.GetMerchantById getMerchantById;
final _merchantByName.GetMerchantsByName getMerchantsByName;
final _merchants.GetMerchants getMerchants;
MerchantBloc({
@required _merchantById.GetMerchantById getMerchantById,
@required _merchantByName.GetMerchantsByName getMerchantsByName,
@required _merchants.GetMerchants getMerchants,
}) : assert(getMerchantById != null),
assert(getMerchantsByName != null),
assert(getMerchants != null),
getMerchantById = getMerchantById,
getMerchantsByName = getMerchantsByName,
getMerchants = getMerchants;
@override
MerchantState get initialState => InitialMerchantState();
@override
Stream<MerchantState> mapEventToState(
MerchantEvent event,
) async* {
if (event is SearchByMerchantNameEvent) {
yield MerchantsLoading();
final failureOrMerchants =
await getMerchantsByName(_merchantByName.Params(name: event.name));
yield* _eitherLoadedMerchantsOrErrorState(failureOrMerchants);
} else if (event is SearchMerchantsEvent) {
yield MerchantsLoading();
final failureOrMerchants = await getMerchants(_merchants.Params(
lat: event.lat,
lng: event.lng,
rad: event.rad,
cat: event.cat,
));
yield* _eitherLoadedMerchantsOrErrorState(failureOrMerchants);
} else if (event is GetMerchantByIdEvent) {
yield MerchantsLoading();
final failureOrMerchant =
await getMerchantById(_merchantById.Params(merchantId: event.id));
yield* _eitherLoadedMerchantOrErrorState(failureOrMerchant);
}
}
Stream<MerchantState> _eitherLoadedMerchantsOrErrorState(
Either<Failure, List<MerchantModel>> failureOrMerchants,
) async* {
yield failureOrMerchants.fold(
(failure) => Error(message: _mapFailureToMessage(failure)),
(merchants) => MerchantsLoaded(merchants: merchants));
}
Stream<MerchantState> _eitherLoadedMerchantOrErrorState(
Either<Failure, MerchantModel> failureOrMerchants,
) async* {
yield failureOrMerchants.fold(
(failure) => Error(message: _mapFailureToMessage(failure)),
(merchant) => MerchantLoaded(merchant: merchant));
}
String _mapFailureToMessage(Failure failure) {
switch (failure.runtimeType) {
case ServerFailure:
return SERVER_FAILURE_MESSAGE;
case CacheFailure:
return CACHE_FAILURE_MESSAGE;
default:
return 'Unexpected error';
}
}
}
Error connecting to the service protocol: HttpException: Connection closed before full header was received, uri = http://127.0.0.1:57777/EPeR8dtjIjQ=/ws
Many thanks for this project and the video tutorial.
You do a fabulous job on making it clear how to apply these abstract design principles to Flutter.
Could you add a license to the project, maybe the GPL v3 like in the other Flutter course you have (flutter-ddd)?
If it's easier for you, I can make a pull request with a LICENSE file.
Thank you for your effort, you made me take a look at Flutter again!
I want to run test, but this error accurs:
Error: Cannot run with sound null safety, because the following dependencies
don't support null safety:
- package:data_connection_checker
For solutions, see https://dart.dev/go/unsound-null-safety
What package is better to replace data_connection_checker?
Hi, I'm new to Flutter.
I facing problem when I try to parsing "complex" json with nested list. How to parsing nested json data in model file, while the entity doesn't contain .fromJson() and .toJson() ?
We know that model class extends entity class.
It's confused me.
Thank you :)
You should add the following line to InputConverter before trying to parse the input as an int:
if (str == null) return Left(InvalidInputFailure());
otherwise an unhandled exception is thrown that is not covered in your exception handling.
测试代码本身也算另一种形式的业务代码,为了保证测试代码的正确。
你给测试代码写测试吗?
你给测试代码的测试代码写测试吗?
你给测试代码的测试代码的测试代码写测试吗?
你给测试代码的测试代码的测试代码的测试代码写测试吗?
你不写,就代表你不会用TDD,你就写不出高质量代码,你就无法重构代码,你就会被程序界开除人籍
Hi Matt
Thanks for the great tutorial. I really enjoyed it.
It seems that if you provide a non-valid URL the app shows the circular activity indicator forever.
I think one should add logic for such a scenario to prevent a bug.
I ran the project tdd clean architector method, but I had a problem with the test wiget. Does the test wiget work with your method?
Please leave a tutorial link🙏
Thanks for this awesome work Reso
After upgrading my flutter SDK, I get a white screen when the app starts, after reading the logs, all you have to do is add WidgetsFlutterBinding.ensureInitialized(); to the main method in main.dart.
And also consider upgrading the app to androidX
I just thought I should point it out to save others from similar frustration because it is heartbreaking to go through all this work and have a white screen in the end.
Again, thanks for the awesome tutorial, it has taught me a lot
Cheers
Random can return infinity, which has a null value for the number field, see json response below
{
"text": "-Infinity is negative infinity.",
"number": null,
"found": true,
"type": "trivia"
}
Hey! I stumbled upon your channel by accident, glad I did! Nice stuff!! I do, however have a couple of questions.
Usually when you go to Clean you end up placing your Business Logic inside your domain so you can eventually reuse it, this (for me) meant that your BLoCs should be a part of that domain layer, however you place them within the Presentation Layer, what is your main reason? My guess is that since it is updating the UI like a ViewModel would do then you are placing it with the screen/view that it is working with.
The way you set up your folder structure also can take a toll whenever developing bigger projects, for example, you have setup domain in each feature but if you need another feature to use the same entities that another feature has, then you would be breaking your own folder proposal. To be honest, that's something I've struggled working with in Flutter. I believe a solution could be to have the presentation layer to be feature grouped and have a more general domain + data layer outside. Going with your app it would look something like:
The app works completely fine in debug and profile modes without any issue. But when trying in release mode it Shows either only a single Number Trivia every time or Cache Failure on both the trivia controls. Please help in fixing this issue.
First thank you very much for the nice clean tutorial.
My question is how would GraphQL subscriptions fit in our current clean architecture?
Thank you very much!
Hi
How can I use widgets or pages of another feature?
Example:
For example, I have an authentication feature, I want to use the login widget of this plugin in the feature of my store, how should I do this?
If I import the widget into my storeframe, the modular structure will be lost, right?
In which layer initialization database should be done ?
Hello,
BLOC tests are failing after upgrading flutter_bloc to 7.0.0. Tried several options and searched web. Did not find suitable answer. Can you please suggest a fix ?
Here is an example test name:
should emit [Error] when the input is invalid
Fails for this expectLater(bloc, emitsInOrder(expected));
In 1.0 dispatch is replaced by add, and in tests you no longer need to use the bloc's state
Hey Matt!
I'm a big fan of your Flutter videos. I've been experimenting with Flutter for some weeks and your guides helped me a lot, thanks!
For this course, as folder structure is really important, I want to ask you if you can add .gitkeep empty files to the empty folders, so we can better follow the fundamentals of the first lesson, or even clone this repository as a template for new projects!
Thanks again and keep the excellent work!
You have this:
class NumberTriviaBloc extends Bloc<NumberTriviaEvent, NumberTriviaState> {
final GetConcreteNumberTrivia getConcreteNumberTrivia;
final GetRandomNumberTrivia getRandomNumberTrivia;
Which is hardcoding a dependency on GetConcreteNumberTrivia and GetRandomNumberTrivia types.
Shouldn't that really be:
class NumberTriviaBloc extends Bloc<NumberTriviaEvent, NumberTriviaState> {
final UseCase<NumberTrivia, Params> getConcreteNumberTrivia;
final UseCase<NumberTrivia, NoParams> getRandomNumberTrivia;
where Params would be a type (probably better named) in entities or better yet just use int instead and make GetConcreteNumberTrivia
implement UseCase<NumberTrivia, int>
I just changed a few things here and there and I encountered this weird problem and solution.
Full details here :-
https://stackoverflow.com/questions/67443531/flutter-using-async-in-testing-produces-an-error-but-using-async-made-it-work
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.