-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Leandro Forte - Flutter Coding Test #75
base: master
Are you sure you want to change the base?
Leandro Forte - Flutter Coding Test #75
Conversation
…ter_create [PROJECT] Flutter Create
…er (pages and cubits)
[FEATURE][Flutter] QR Code Scan
[FEATURE][Flutter] QR Code Scan
[FEATURE] NodeJS Backend
…source and adjusting its tests
…_node [FEATURE] Connect Flutter to Node
[FEATURE] Add NodeJS backend and connect Flutter into it
[BUGFIX] Expires At
[BUGFIX] Expires At
[PROJECT] Documentation
[PROJECT] Documentation
[PROJECT] Documentation
[PROJECT] Documentation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work!
I think you have a solid understanding of domain layers, their responsibilities, and how they interact with each other. It is great to see that you tested all layers as well.
On the presentation side, I saw attention to detail and code organization with the cubit responsibilities.
cupertino_icons: ^1.0.2 | ||
bloc: ^8.1.2 | ||
flutter_bloc: ^8.1.3 | ||
bloc_test: ^9.1.5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bloc_test should be a dev dependency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. I'll pay more attention to that. Thanks.
bloc_test: ^9.1.5 | ||
dartz: ^0.10.1 | ||
equatable: ^2.0.5 | ||
mocktail: ^1.0.3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mocktail should be a dev dependency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. I'll pay more attention to that. Thanks.
|
||
extension BuildContextExtension on BuildContext { | ||
double get screenWidth => MediaQuery.of(this).size.width; | ||
TextTheme get textTheme => Theme.of(this).textTheme; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kudos: nice!
|
||
sealed class DioInject { | ||
static Future<void> inject() async { | ||
getIt.registerFactory<Dio>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: why a factory and not a singleton?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I should have used singleton for that knowing the singleton will create the instance only when called.
I'll pay more attention to that. Thanks.
|
||
@override | ||
void dispose() { | ||
_timerCubit.disposeTimer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: great catch disposing the timer if disposing the screen, butyou can also dispose the timer on the cubit's dispose method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, of course. Thanks.
final double dimension; | ||
|
||
@override | ||
Widget build(BuildContext context) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kudos: nice laoding animation
BlocBuilder<TimerCubit, TimerState>( | ||
bloc: _timerCubit, | ||
builder: (context, state) { | ||
return switch (state) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kudos: dart 3 ussage
|
||
test( | ||
'should get QR code from the repository and check if it was called once', | ||
() async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kudos: for testing all layers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Based on the path (lib/features/qr_code_scan/domain/repositories
), do you consider that repositories belong to the domain layer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the Clean Architecture concept, I know the repository belongs to the data layer, but I like to create only the abstract class in the domain folder and the implementation class in the data folder just to represent the connection between the domain and data layers.
Thanks.
import 'package:superformula_leandro/core/errors/failures/failure.dart'; | ||
import 'package:superformula_leandro/features/qr_code_scan/domain/entities/qr_code_entity.dart'; | ||
|
||
abstract interface class GetQrCodeRepository { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Could you explain why you named the repository GetQrCodeRepository
and not just QrCodeRepository
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. I forgot to rename it. I'll pay more attention to that. Thanks.
import 'package:superformula_leandro/features/qr_code_scan/presenter/cubits/scan/scan_cubit.dart'; | ||
import 'package:superformula_leandro/features/qr_code_scan/presenter/pages/scan/widgets/scanned_data_body_widget.dart'; | ||
|
||
class ScanPage extends StatefulWidget { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Could you explain why you preferred using a StatefulWidget
instead of an StatelessWidget
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to initialize the ScanCubt from the context.read and after call the startScan method only in the beginning of the page lifecycle.
Theres another way to do that, using StatelessWidget and calling the startScan method when the state is the ScanInitialState.
Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about doing it when instantiating the cubit? Do you see any inconvenient with this approach?
BlocProvider<ScanCubit>(
create: (context) => ScanCubit()..startScan(),
child: const ScanPage(),
),
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No inconvenient at all. That's a really good way to do that as well. Thanks.
padding: const EdgeInsets.all(16), | ||
child: Center( | ||
child: BlocBuilder<ScanCubit, ScanState>( | ||
bloc: _scanCubit, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Do you think it's necessary to pass bloc as parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like to use this parameter to make the understanding of the code easier. For example, if a page has a lot of cubits, this parameter I'll helps who is reading to understand what that widget is responsible for.
Thanks.
), | ||
), | ||
bottomNavigationBar: BlocBuilder<ScanCubit, ScanState>( | ||
bloc: _scanCubit, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Maybe you could have used buildWhen
to avoid unnecessary rebuilds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's necessary because in this page, I need to rebuild this bottomsheet every time cubit emits something.
I have the emitted states: ScanningState, ScanErrorState and ScannedDataState and I need to only show when It's ScannedDataState.
For example, If I've had the buildWhen: (_, current) => current is ScannedDataState, when emits another state the bottomsheet will not disappear and I don't want it.
Don't you think so?
Anyway, thanks for noticing that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could use the following condition, what do you think?
buildWhen: (previous, current) {
return (previous is ScannedDataState) ^ (current is ScannedDataState);
},
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yess. This should work, you're right. Thanks.
Hi guys. I replied to all your comments. I really appreciate all your feedbacks and I'm looking forward for the next steps. Feel free to reach me out to anything. Thanks one more time. |
Hey guys,
Hope this message finds you well
The documentation is the app-documentation.md file in the project root folder
Thank you for the opportunity
See you later