Generated by the Very Good CLI 🤖
- The user can view/delete posts from service json_url.
- The user can add posts to favorite.
- Flutter Bloc : State management & built in testing support.
- Dio : Handling network calls.
- Easy Loading : Handling loading states.
- Hive Flutter : Handling caching of the posts.
- Freezed & Json Serializable: Data classes and Json serialization.
- Mocktail : For mocking dependencies for testing purposes.
- Very Good Cli : Quickly bootstrapping projects with standard practices.
- Layered architecture with a good separation of concerns between the presentation layer, business logic, repositories & the network layer.
- Tested code. (Widget, Unit Tests. Need to add some Integration Tests)
- In par with the Test Pyramid
- Created two different packages - posts_repository and posts_api_client. Only posts_api_client can make the network calls with the help of Dio and can cache the posts using Hive. Posts repository interacts with the posts_api_client for functionalities. This way code is more independent and reusable.
- Hive greatly outperforms SQLite and SharedPreferences when it comes to writing or deleting which is why Hive has been used to handle caching.
- Cubit has been used for state management. It interacts with the posts_repository and updates the state by which widget renders according to it. Cubit is a simple state management that abandons the concept of events from BloC to make emitting states easier. In the case of app, BloC is not needed in my opinion.
- Using separate cubit to handle favorites with bloc to bloc communication acting as means to handle posts and favorite. This can implemented later with more time.
- Could have used same hive box to store favorites by adding isFavorite parameter to the Post model.
- In this project, there is a separate hive box to store the favorite posts which has kept everything well separated and easy for modification. Only con is that, there is an extra hive box created for this.
- More fined grained exception handling.
- Whiteboard different approaches for caching.
- Fix redundant and incomplete documentations.
- Refactor the tests to follow the robot testing pattern for better readability and maintenance.
- Add integration and E2E tests.
- Add proper internationalization using the l10n library.
This project contains 3 flavors:
- development
- staging
- production
To run the desired flavor either use the launch configuration in VSCode/Android Studio or use the following commands:
# Development
$ flutter run --flavor development --target lib/main_development.dart
# Staging
$ flutter run --flavor staging --target lib/main_staging.dart
# Production
$ flutter run --flavor production --target lib/main_production.dart
*Zemoga Posts works on iOS, Android, Web, and Windows.
To run all unit and widget tests use the following command:
$ sh test.sh
To view the generated coverage report you can use lcov.
# Generate Coverage Report
$ genhtml coverage/lcov.info -o coverage/
# Open Coverage Report
$ open coverage/index.html
This project relies on flutter_localizations and follows the official internationalization guide for Flutter.
- To add a new localizable string, open the
app_en.arb
file atlib/l10n/arb/app_en.arb
.
{
"@@locale": "en",
"counterAppBarTitle": "Counter",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
}
}
- Then add a new key/value and description
{
"@@locale": "en",
"counterAppBarTitle": "Counter",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
"helloWorld": "Hello World",
"@helloWorld": {
"description": "Hello World Text"
}
}
- Use the new string
import 'package:zemoga_posts/l10n/l10n.dart';
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Text(l10n.helloWorld);
}
Update the CFBundleLocalizations
array in the Info.plist
at ios/Runner/Info.plist
to include the new locale.
...
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>es</string>
</array>
...
- For each supported locale, add a new ARB file in
lib/l10n/arb
.
├── l10n
│ ├── arb
│ │ ├── app_en.arb
│ │ └── app_es.arb
- Add the translated strings to each
.arb
file:
app_en.arb
{
"@@locale": "en",
"counterAppBarTitle": "Counter",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
}
}
app_es.arb
{
"@@locale": "es",
"counterAppBarTitle": "Contador",
"@counterAppBarTitle": {
"description": "Texto mostrado en la AppBar de la página del contador"
}
}