This project is a Flutter-based user management application that demonstrates full CRUD (Create, Read, Update, Delete) operations. The app interacts with a RESTful API to manage users and their associated data, including posts, todos, and comments.
A key feature of this application is its flexible backend architecture. Developers can seamlessly switch between two data sources:
- The public GoRest API (
https://gorest.co.in/) - A custom, self-hosted backend built with Spring Boot and Kotlin
This choice is managed through environment variables, putting the decision of which backend to use entirely in the hands of the user.
- User Management: Browse, add, edit, and delete user profiles.
- User Content: View and manage detailed user information, including their posts, todos, and comments.
- API Operations: Utilizes all standard HTTP methods (GET, POST, PUT, DELETE) to interact with the API endpoints.
- Backend Agnostic: Configure the app to run against the free GoRest service or your own private Kotlin/Spring Boot backend for full control and offline development.
- Frontend: Flutter
- Backend Options:
- GoRest API: A free-to-use online REST API.
- Custom Backend: Spring Boot with Kotlin and PostgreSQL, replicating the GoRest functionality.
The app supports multiple backend configurations through environment variables. By passing the BACKEND flag at runtime, you can select which backend the app should use:
- Run with GoREST backend:
flutter run --dart-define=BACKEND=gorestEnv
- Run with Custom Backend:
flutter run --dart-define=BACKEND=springEnv
Configuration details for each backend are stored in separate JSON files inside the assets/config/ directory:
gorest_config.jsonspring_config.json
When using the custom Spring Boot backend, the backend_url in spring_config.json must point to the correct host depending on the environment:
{
"backend_url": "http://10.0.3.2:8080"
}{
"backend_url": "http://10.0.2.2:8080"
}spring_config.json according to the emulator you are using, otherwise the app will not be able to connect to your Spring Boot backend.
| User screen | Create-update User | Todo screen | Post screen |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
| Date picker | Time picker | Create-update post | Comment Screen |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
| Error state | Empty state | Warning dialog | Progress dialog |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
-
Different implementations with separate modules based on state management solutions and software architectures
-
Clean architecture / MVVM architecture / simple layered architecture
-
Feature-first and Layer-first approach
-
Performing CRUD operation using
Dioand go rest api -
Converting JSON string to an equivalent dart object and vice versa with
json serializable -
Implementing Interceptors, Global configuration and timeout for api calls
-
Exception Handling with Dio interceptor,
Dartzandfreezed -
Dependency injection with
get it(Clean architecture / MVVM architecture version) -
Displaying error type to the user through the alert dialogs
-
Colorize api info like request, response, body and exceptions in Debug console log
-
Read, create, update and delete user
-
Filter users by status activity or gender
-
Read, create, update and delete user todos
-
Filter todos by status
-
Read, create, update and delete user posts
-
Display, create and delete user comments for each post
-
Get date/time from user by Date/Time picker
-
Generic structure
-
State management with
GetX|Bloc|Cubit|RxDart -
Unit testing (Clean architecture version (GetX))
In this repository, two architectural approaches have been implemented: Feature-First and Layer-First.
-
Feature-First Approach (used in the Clean Architecture and Simple Layered Architecture versions):
A new folder is created for each feature added to the app. Inside each feature folder, the layers (e.g., data, domain, presentation) are organized as subfolders. -
Layer-First Approach (used in the MVVM Architecture version):
All files are grouped by their respective layers firs
When using the GoREST API, there are some important limitations to be aware of:
- The
usersendpoint always contains 10 user objects by default. - If any of them are deleted, they are automatically replaced with new placeholder data.
- As a result:
- The user list will always remain 10 items long.
- It is not possible to create more than 10 users.
- Query parameters on the
usersendpoint are limited in functionality.
- To use PUT, POST, PATCH, or DELETE requests, an access token must be provided in the
Authorizationheader as a Bearer token. - A token has already been included in the app configuration.
- If a
401 Unauthorizederror occurs, a new token must be requested here and updated in theapi_configfile located in thecoredirectory.
- The API data is not permanent.
- It is refreshed or cleared every 20 minutes to 1 hour, meaning any changes will not persist for long.
When using the custom Spring Boot backend, all of the above limitations are removed:
- Unlimited creation and management of users, posts, todos, and comments.
- No external access token is required.
- Data is stored in a real PostgreSQL database and persists permanently.
| Version | Bloc | Cubit | Getx | RxDart + Provider |
|---|---|---|---|---|
| Clean architecture version | Source️ | Source | Source | Source |
| MVVM architecture version | Source | Source️ | Source️ | |
| Simple layered architecture version | Source | Source | Source |
| Name | GetX | Cubit | Bloc | RxDart + Provider |
|---|---|---|---|---|
| flutter_bloc | ✖️ | ✔ | ✔ | ✖ |
| provider | ✖️ | ✖ | ✖ | ✔ |
| rxdart | ✖️ | ✖ | ✖ | ✔ |
| get_it | ✔️ | ✔ | ✔ | ✔ |
| GetX | ✔️ | ✖️ | ✖️ | ✖ |
| dio | ✔️ | ✔️ | ✔️ | ✔ |
| freezed | ✖️ | ✔️ | ✔️ | ✔ |
| freezed_annotation | ✖ | ✔️ | ✔️ | ✔ |
| json_annotation | ✔️ | ✔️ | ✔️ | ✔ |
| json_serializable | ✔️ | ✔️ | ✔️ | ✔ |
| build_runner | ✔️ | ✔️ | ✔️ | ✔ |
| logger | ✔️ | ✔️ | ✔️ | ✔ |
| dartz | ✔️ | ✖️ | ✖️ | ✖ |
| flutter_spinkit | ✔️ | ✔️ | ✔️ | ✔ |
| intl | ✔️ | ✔️ | ✔️ | ✔ |
| mockito | ✔️ | ✖️ | ✖️ | ✖ |
| Name | GetX | Cubit | Bloc |
|---|---|---|---|
| flutter_bloc | ✖️ | ✔ | ✔ |
| get_it | ✔️ | ✔ | ✔ |
| GetX | ✔️ | ✖️ | ✖️ |
| dio | ✔️ | ✔️ | ✔️ |
| freezed | ✖️ | ✔️ | ✔️ |
| freezed_annotation | ✖ | ✔️ | ✔️ |
| json_annotation | ✔️ | ✔️ | ✔️ |
| json_serializable | ✔️ | ✔️ | ✔️ |
| build_runner | ✔️ | ✔️ | ✔️ |
| logger | ✔️ | ✔️ | ✔️ |
| dartz | ✔️ | ✖️ | ✖️ |
| flutter_spinkit | ✔️ | ✔️ | ✔️ |
| intl | ✔️ | ✔️ | ✔️ |
| Name | GetX | Cubit | Bloc |
|---|---|---|---|
| flutter_bloc | ✖️ | ✔ | ✔ |
| GetX | ✔️ | ✖️ | ✖️ |
| dio | ✔️ | ✔️ | ✔️ |
| freezed | ✖️ | ✔️ | ✔️ |
| freezed_annotation | ✖ | ✔️ | ✔️ |
| json_annotation | ✔️ | ✔️ | ✔️ |
| json_serializable | ✔️ | ✔️ | ✔️ |
| build_runner | ✔️ | ✔️ | ✔️ |
| logger | ✔️ | ✔️ | ✔️ |
| dartz | ✔️ | ✖️ | ✖️ |
| flutter_spinkit | ✔️ | ✔️ | ✔️ |
| intl | ✔️ | ✔️ | ✔️ |
┌─── GorestBackendApplication.kt
│
│───📂controller
│ │── CommentController
│ │── PostController
│ │── TodoController
│ └── UserController
│
│───📂converter
│ └── Converter.kt
│
│───📂dto
│ │── CommentDto
│ │── PostDto
│ │── TodoDto
│ └── UserDto
│
│───📂entity
│ │── CommentEntity
│ │── PostEntity
│ │── TodoEntity
│ └── UserEntity
│
│───📂mapper
│ │── CommentMapper.kt
│ │── PostMapper.kt
│ │── TodoMapper.kt
│ └── UserMapper.kt
│
│───📂repository
│ │── CommentRepository
│ │── PostRepository
│ │── TodoRepository
│ └── UserRepository
│
│───📂service
│ │── CommentService
│ │── PostService
│ │── TodoService
│ └── UserService
│
└───📂validation
│── CustomException.kt
│── ErrorResponse
│── GlobalExceptionHandler.kt
└── GlobalExceptionHandler
📂lib
│───main.dart
│───di.dart
│───📂common
│ │───📂bloc
│ │ │──bloc_helper.dart
│ │ │──generic_bloc_state.dart
│ │ └──generic_bloc_builder.dart
│ │───📂usecase
│ │ └──usecase.dart
│ │───📂repository
│ │ └──repository_helper.dart
│ │───📂network
│ │ │──api_config.dart
│ │ │──api_helper.dart
│ │ │──api_result.dart
│ │ │──api_result.freezed.dart
│ │ │──dio_client.dart
│ │ │──dio_exception.dart
│ │ └──dio_interceptor.dart
│ │───📂widget
│ │ │──date_time_picker.dart
│ │ │──drop_down.dart
│ │ │──empty_widget.dart
│ │ │──popup_menu.dart
│ │ │──spinkit_indicator.dart
│ │ └──text_input.dart
│ └───📂dialog
│ │──create_dialog.dart
│ │──delete_dialog.dart
│ │──progress_dialog.dart
│ └──retry_dialog.dart
│───📂core
│ │──app_asset.dart
│ │──app_extension.dart
│ │──app_string.dart
│ │──app_style.dart
│ └──app_theme.dart
│
└───📂features
│───📂user
│ │───📂data
│ │ │──📂datasources
│ │ │ └──user_remote_data_source.dart
│ │ │──📂models
│ │ │ │──user.dart
│ │ │ └──user.g.dart
│ │ └──📂repositories
│ │ └──user_repository_impl.dart
│ │───📂domain
│ │ │───📂entities
│ │ │ └──user_entity.dart
│ │ │───📂repositories
│ │ │ └──user_repository.dart
│ │ │───📂usecases
│ │ │ │──create_user_usecase.dart
│ │ │ │──delete_user_usecase.dart
│ │ │ │──get_users_usecase.dart
│ │ │ └──update_user_usecase.dart
│ └── 📂presentation
│ │───📂bloc
│ │ │──user_bloc.dart
│ │ └──user_event.dart
│ │───📂screens
│ │ └──user_list_screen.dart
│ └───📂widgets
│ └──status_container.dart
│
│───📂todo
│ │───📂data
│ │ │──📂datasources
│ │ │ └──todo_remote_data_source.dart
│ │ │──📂models
│ │ │ │──todo.dart
│ │ │ └──todo.g.dart
│ │ └──📂repositories
│ │ └──todo_repository_impl.dart
│ │───📂domain
│ │ │───📂entities
│ │ │ └──todo_entity.dart
│ │ │───📂repositories
│ │ │ └──todo_repository.dart
│ │ │───📂usecases
│ │ │ │──create_todo_usecase.dart
│ │ │ │──delete_todo_usecase.dart
│ │ │ │──get_todos_usecase.dart
│ │ │ └──update_todo_usecase.dart
│ └── 📂presentation
│ │───📂bloc
│ │ │──todo_bloc.dart
│ │ └──todo_event.dart
│ │───📂screens
│ │ └──todo_list_screen.dart
│ └───📂widgets
│ │──circle_container.dart
│ └──todo_list_item.dart
│───📂post
│ │───📂data
│ │ │──📂datasources
│ │ │ └──post_remote_data_source.dart
│ │ │──📂models
│ │ │ │──post.dart
│ │ │ └──post.g.dart
│ │ └──📂repositories
│ │ └──post_repository_impl.dart
│ │───📂domain
│ │ │───📂entities
│ │ │ └──post_entity.dart
│ │ │───📂repositories
│ │ │ └──post_repository.dart
│ │ │───📂usecases
│ │ │ │──create_post_usecase.dart
│ │ │ │──delete_post_usecase.dart
│ │ │ │──get_posts_usecase.dart
│ │ │ └──update_post_usecase.dart
│ └── 📂presentation
│ │───📂bloc
│ │ │──post_bloc.dart
│ │ └──post_event.dart
│ └───📂screens
│ │──create_post_screen.dart
│ │──post_detail_screen.dart
│ └──post_list_screen.dart
└───📂comment
│───📂data
│ │──📂datasources
│ │ └──comment_remote_data_source.dart
│ │──📂models
│ │ │──comment.dart
│ │ └──comment.g.dart
│ └──📂repositories
│ └──comment_repository_impl.dart
│───📂domain
│ │───📂entities
│ │ └──comment_entity.dart
│ │───📂repositories
│ │ └──comment_repository.dart
│ │───📂usecases
│ │ │──create_comment_usecase.dart
│ │ │──delete_comment_usecase.dart
│ │ └──get_comments_usecase.dart
└── 📂presentation
└───📂bloc
│──comment_bloc.dart
└──comment_event.dart
📂lib
│───main.dart
│───di.dart
│───📂common
│ │───📂cubit
│ │ │──generic_cubit.dart
│ │ └──generic_cubit_state.dart
│ │───📂usecase
│ │ └──usecase.dart
│ │───📂repository
│ │ └──repository_helper.dart
│ │───📂network
│ │ │──api_config.dart
│ │ │──api_helper.dart
│ │ │──api_result.dart
│ │ │──api_result.freezed.dart
│ │ │──dio_client.dart
│ │ │──dio_exception.dart
│ │ └──dio_interceptor.dart
│ │───📂widget
│ │ │──date_time_picker.dart
│ │ │──drop_down.dart
│ │ │──empty_widget.dart
│ │ │──popup_menu.dart
│ │ │──spinkit_indicator.dart
│ │ └──text_input.dart
│ └───📂dialog
│ │──create_dialog.dart
│ │──delete_dialog.dart
│ │──progress_dialog.dart
│ └──retry_dialog.dart
│───📂core
│ │──app_asset.dart
│ │──app_extension.dart
│ │──app_string.dart
│ │──app_style.dart
│ └──app_theme.dart
│
└───📂features
│───📂user
│ │───📂data
│ │ │──📂datasources
│ │ │ └──user_remote_data_source.dart
│ │ │──📂models
│ │ │ │──user.dart
│ │ │ └──user.g.dart
│ │ └──📂repositories
│ │ └──user_repository_impl.dart
│ │───📂domain
│ │ │───📂entities
│ │ │ └──user_entity.dart
│ │ │───📂repositories
│ │ │ └──user_repository.dart
│ │ │───📂usecases
│ │ │ │──create_user_usecase.dart
│ │ │ │──delete_user_usecase.dart
│ │ │ │──get_users_usecase.dart
│ │ │ └──update_user_usecase.dart
│ └── 📂presentation
│ │───📂cubit
│ │ └──user_cubit.dart
│ │───📂screens
│ │ └──user_list_screen.dart
│ └───📂widgets
│ └──status_container.dart
│
│───📂todo
│ │───📂data
│ │ │──📂datasources
│ │ │ └──todo_remote_data_source.dart
│ │ │──📂models
│ │ │ │──todo.dart
│ │ │ └──todo.g.dart
│ │ └──📂repositories
│ │ └──todo_repository_impl.dart
│ │───📂domain
│ │ │───📂entities
│ │ │ └──todo_entity.dart
│ │ │───📂repositories
│ │ │ └──todo_repository.dart
│ │ │───📂usecases
│ │ │ │──create_todo_usecase.dart
│ │ │ │──delete_todo_usecase.dart
│ │ │ │──get_todos_usecase.dart
│ │ │ └──update_todo_usecase.dart
│ └── 📂presentation
│ │───📂cubit
│ │ └──todo_cubit.dart
│ │───📂screens
│ │ └──todo_list_screen.dart
│ └───📂widgets
│ │──circle_container.dart
│ └──todo_list_item.dart
│───📂post
│ │───📂data
│ │ │──📂datasources
│ │ │ └──post_remote_data_source.dart
│ │ │──📂models
│ │ │ │──post.dart
│ │ │ └──post.g.dart
│ │ └──📂repositories
│ │ └──post_repository_impl.dart
│ │───📂domain
│ │ │───📂entities
│ │ │ └──post_entity.dart
│ │ │───📂repositories
│ │ │ └──post_repository.dart
│ │ │───📂usecases
│ │ │ │──create_post_usecase.dart
│ │ │ │──delete_post_usecase.dart
│ │ │ │──get_posts_usecase.dart
│ │ │ └──update_post_usecase.dart
│ └── 📂presentation
│ │───📂cubit
│ │ └──post_cubit.dart
│ └───📂screens
│ │──create_post_screen.dart
│ │──post_detail_screen.dart
│ └──post_list_screen.dart
└───📂comment
│───📂data
│ │──📂datasources
│ │ └──comment_remote_data_source.dart
│ │──📂models
│ │ │──comment.dart
│ │ └──comment.g.dart
│ └──📂repositories
│ └──comment_repository_impl.dart
│───📂domain
│ │───📂entities
│ │ └──comment_entity.dart
│ │───📂repositories
│ │ └──comment_repository.dart
│ │───📂usecases
│ │ │──create_comment_usecase.dart
│ │ │──delete_comment_usecase.dart
│ │ └──get_comments_usecase.dart
└── 📂presentation
└───📂cubit
└──comment_cubit.dart
📂lib
│───main.dart
│───di.dart
│───📂common
│ │───📂bloc
│ │ └──generic_bloc_state.dart
│ │───📂usecase
│ │ └──usecase.dart
│ │───📂repository
│ │ └──repository_helper.dart
│ │───📂network
│ │ │──api_config.dart
│ │ │──api_helper.dart
│ │ │──api_result.dart
│ │ │──api_result.freezed.dart
│ │ │──dio_client.dart
│ │ │──dio_exception.dart
│ │ └──dio_interceptor.dart
│ │───📂widget
│ │ │──date_time_picker.dart
│ │ │──drop_down.dart
│ │ │──empty_widget.dart
│ │ │──popup_menu.dart
│ │ │──spinkit_indicator.dart
│ │ └──text_input.dart
│ └───📂dialog
│ │──create_dialog.dart
│ │──delete_dialog.dart
│ │──progress_dialog.dart
│ └──retry_dialog.dart
│───📂core
│ │──app_asset.dart
│ │──app_extension.dart
│ │──app_string.dart
│ │──app_style.dart
│ └──app_theme.dart
│
└───📂features
│───📂user
│ │───📂data
│ │ │──📂datasources
│ │ │ └──user_remote_data_source.dart
│ │ │──📂models
│ │ │ │──user.dart
│ │ │ └──user.g.dart
│ │ └──📂repositories
│ │ └──user_repository_impl.dart
│ │───📂domain
│ │ │───📂entities
│ │ │ └──user_entity.dart
│ │ │───📂repositories
│ │ │ └──user_repository.dart
│ │ │───📂usecases
│ │ │ │──create_user_usecase.dart
│ │ │ │──delete_user_usecase.dart
│ │ │ │──get_users_usecase.dart
│ │ │ └──update_user_usecase.dart
│ └── 📂presentation
│ │───📂bloc
│ │ │──user_bloc.dart
│ │ └──user_event.dart
│ │───📂screens
│ │ └──user_list_screen.dart
│ └───📂widgets
│ └──status_container.dart
│
│───📂todo
│ │───📂data
│ │ │──📂datasources
│ │ │ └──todo_remote_data_source.dart
│ │ │──📂models
│ │ │ │──todo.dart
│ │ │ └──todo.g.dart
│ │ └──📂repositories
│ │ └──todo_repository_impl.dart
│ │───📂domain
│ │ │───📂entities
│ │ │ └──todo_entity.dart
│ │ │───📂repositories
│ │ │ └──todo_repository.dart
│ │ │───📂usecases
│ │ │ │──create_todo_usecase.dart
│ │ │ │──delete_todo_usecase.dart
│ │ │ │──get_todos_usecase.dart
│ │ │ └──update_todo_usecase.dart
│ └── 📂presentation
│ │───📂bloc
│ │ │──todo_bloc.dart
│ │ └──todo_event.dart
│ │───📂screens
│ │ └──todo_list_screen.dart
│ └───📂widgets
│ │──circle_container.dart
│ └──todo_list_item.dart
│───📂post
│ │───📂data
│ │ │──📂datasources
│ │ │ └──post_remote_data_source.dart
│ │ │──📂models
│ │ │ │──post.dart
│ │ │ └──post.g.dart
│ │ └──📂repositories
│ │ └──post_repository_impl.dart
│ │───📂domain
│ │ │───📂entities
│ │ │ └──post_entity.dart
│ │ │───📂repositories
│ │ │ └──post_repository.dart
│ │ │───📂usecases
│ │ │ │──create_post_usecase.dart
│ │ │ │──delete_post_usecase.dart
│ │ │ │──get_posts_usecase.dart
│ │ │ └──update_post_usecase.dart
│ └── 📂presentation
│ │───📂bloc
│ │ └──post_bloc.dart
│ └───📂screens
│ │──create_post_screen.dart
│ │──post_detail_screen.dart
│ └──post_list_screen.dart
└───📂comment
│───📂data
│ │──📂datasources
│ │ └──comment_remote_data_source.dart
│ │──📂models
│ │ │──comment.dart
│ │ └──comment.g.dart
│ └──📂repositories
│ └──comment_repository_impl.dart
│───📂domain
│ │───📂entities
│ │ └──comment_entity.dart
│ │───📂repositories
│ │ └──comment_repository.dart
│ │───📂usecases
│ │ │──create_comment_usecase.dart
│ │ │──delete_comment_usecase.dart
│ │ └──get_comments_usecase.dart
└── 📂presentation
└───📂bloc
└──comment_bloc.dart
root
│── 📂coverage
│── 📂lib
│ │───main.dart
│ │───di.dart
│ │───📂common
│ │ │───📂controller
│ │ │ └──base_controller.dart
│ │ │───📂usecase
│ │ │ └──usecase.dart
│ │ │───📂repository
│ │ │ └──repository_helper.dart
│ │ │───📂network
│ │ │ │──api_config.dart
│ │ │ │──api_base.dart
│ │ │ │──dio_client.dart
│ │ │ │──dio_exception.dart
│ │ │ └──dio_interceptor.dart
│ │ │───📂widget
│ │ │ │──date_time_picker.dart
│ │ │ │──drop_down.dart
│ │ │ │──empty_widget.dart
│ │ │ │──popup_menu.dart
│ │ │ │──spinkit_indicator.dart
│ │ │ └──text_input.dart
│ │ └───📂dialog
│ │ │──create_dialog.dart
│ │ │──delete_dialog.dart
│ │ │──progress_dialog.dart
│ │ └──retry_dialog.dart
│ │───📂core
│ │ │──app_asset.dart
│ │ │──app_extension.dart
│ │ │──app_string.dart
│ │ │──app_style.dart
│ │ └──app_theme.dart
│ │
│ └───📂features
│ │───📂user
│ │ │───📂data
│ │ │ │──📂datasources
│ │ │ │ └──user_remote_data_source.dart
│ │ │ │──📂models
│ │ │ │ │──user.dart
│ │ │ │ └──user.g.dart
│ │ │ └──📂repositories
│ │ │ └──user_repository_impl.dart
│ │ │───📂domain
│ │ │ │───📂entities
│ │ │ │ └──user_entity.dart
│ │ │ │───📂repositories
│ │ │ │ └──user_repository.dart
│ │ │ │───📂usecases
│ │ │ │ │──create_user_usecase.dart
│ │ │ │ │──delete_user_usecase.dart
│ │ │ │ │──get_users_usecase.dart
│ │ │ │ └──update_user_usecase.dart
│ │ └── 📂presentation
│ │ │───📂controller
│ │ │ └──user_controller.dart
│ │ │───📂screens
│ │ │ └──user_list_screen.dart
│ │ └───📂widgets
│ │ └──status_container.dart
│ │
│ │───📂todo
│ │ │───📂data
│ │ │ │──📂datasources
│ │ │ │ └──todo_remote_data_source.dart
│ │ │ │──📂models
│ │ │ │ │──todo.dart
│ │ │ │ └──todo.g.dart
│ │ │ └──📂repositories
│ │ │ └──todo_repository_impl.dart
│ │ │───📂domain
│ │ │ │───📂entities
│ │ │ │ └──todo_entity.dart
│ │ │ │───📂repositories
│ │ │ │ └──todo_repository.dart
│ │ │ │───📂usecases
│ │ │ │ │──create_todo_usecase.dart
│ │ │ │ │──delete_todo_usecase.dart
│ │ │ │ │──get_todos_usecase.dart
│ │ │ │ └──update_todo_usecase.dart
│ │ └── 📂presentation
│ │ │───📂controller
│ │ │ └──todo_controller.dart
│ │ │───📂screens
│ │ │ └──todo_list_screen.dart
│ │ └───📂widgets
│ │ │──circle_container.dart
│ │ └──todo_list_item.dart
│ │───📂post
│ │ │───📂data
│ │ │ │──📂datasources
│ │ │ │ └──post_remote_data_source.dart
│ │ │ │──📂models
│ │ │ │ │──post.dart
│ │ │ │ └──post.g.dart
│ │ │ └──📂repositories
│ │ │ └──post_repository_impl.dart
│ │ │───📂domain
│ │ │ │───📂entities
│ │ │ │ └──post_entity.dart
│ │ │ │───📂repositories
│ │ │ │ └──post_repository.dart
│ │ │ │───📂usecases
│ │ │ │ │──create_post_usecase.dart
│ │ │ │ │──delete_post_usecase.dart
│ │ │ │ │──get_posts_usecase.dart
│ │ │ │ └──update_post_usecase.dart
│ │ └── 📂presentation
│ │ │───📂controller
│ │ │ └──post_controller.dart
│ │ └───📂screens
│ │ │──create_post_screen.dart
│ │ │──post_detail_screen.dart
│ │ └──post_list_screen.dart
│ └───📂comment
│ │───📂data
│ │ │──📂datasources
│ │ │ └──comment_remote_data_source.dart
│ │ │──📂models
│ │ │ │──comment.dart
│ │ │ └──comment.g.dart
│ │ └──📂repositories
│ │ └──comment_repository_impl.dart
│ │───📂domain
│ │ │───📂entities
│ │ │ └──comment_entity.dart
│ │ │───📂repositories
│ │ │ └──comment_repository.dart
│ │ │───📂usecases
│ │ │ │──create_comment_usecase.dart
│ │ │ │──delete_comment_usecase.dart
│ │ │ └──get_comments_usecase.dart
│ └── 📂presentation
│ └───📂controller
│ └──comment_controller.dart
│
│
│
└── 📂test
│──📂test_utils
│ └─── 📂data
│ └───test_data.dart
│──📂common
│ │─── 📂network
│ │ └───dio_exception_test.dart
│ └─── 📂repository
│ └───repository_helper_test.dart
│──📂core
│ └───app_extension_test.dart
│
└──📂features
│───📂user
│ │───📂data
│ │ │──📂datasources
│ │ │ │──user_remote_data_source_test.dart
│ │ │ └──user_remote_data_source_test.mocks.dart
│ │ └──📂repositories
│ │ │──user_repository_impl_test.dart
│ │ └──user_repository_impl_test.mocks.dart
│ │───📂domain
│ │ │───📂usecases
│ │ │ │──create_user_usecase_test.dart
│ │ │ │──create_user_usecase_test.mocks.dart
│ │ │ │──delete_user_usecase_test.dart
│ │ │ │──get_users_usecase_test.dart
│ │ │ └──update_user_usecase_test.dart
│ └── 📂presentation
│ └───📂controller
│ └──user_controller_test.dart
│ └──user_controller_test.mocks.dart
│
│───📂todo
│ │───📂data
│ │ │──📂datasources
│ │ │ │──todo_remote_data_source_test.dart
│ │ │ └──todo_remote_data_source_test.mocks.dart
│ │ └──📂repositories
│ │ │──todo_repository_impl_test.dart
│ │ └──todo_repository_impl_test.mocks.dart
│ │───📂domain
│ │ │───📂usecases
│ │ │ │──create_todo_usecase_test.dart
│ │ │ │──create_todo_usecase_test.mocks.dart
│ │ │ │──delete_todo_usecase_test.dart
│ │ │ │──get_todos_usecase_test.dart
│ │ │ └──update_todo_usecase_test.dart
│ └── 📂presentation
│ └───📂controller
│ │──todo_controller_test.dart
│ └──todo_controller_test.mocks.dart
│───📂post
│ │───📂data
│ │ │──📂datasources
│ │ │ │──post_remote_data_source_test.dart
│ │ │ └──post_remote_data_source_test.mocks.dart
│ │ └──📂repositories
│ │ │──post_repository_impl_test.dart
│ │ └──post_repository_impl_test.mocks.dart
│ │───📂domain
│ │ │───📂usecases
│ │ │ │──create_post_usecase_test.dart
│ │ │ │──create_post_usecase_test.mocks.dart
│ │ │ │──delete_post_usecase_test.dart
│ │ │ │──get_posts_usecase_test.dart
│ │ │ └──update_post_usecase_test.dart
│ └── 📂presentation
│ └───📂controller
│ │──post_controller_test.dart
│ └──post_controller_test.mocks.dart
└───📂comment
│───📂data
│ │──📂datasources
│ │ │──comment_remote_data_source_test.dart
│ │ └──comment_remote_data_source_test.mocks.dart
│ └──📂repositories
│ │──comment_repository_impl_test.dart
│ └──comment_repository_impl_test.mocks.dart
│───📂domain
│ │───📂usecases
│ │ │──create_comment_usecase_test.dart
│ │ │──create_comment_usecase.mocks.dart
│ │ │──delete_comment_usecase_test.dart
│ │ └──get_comments_usecase_test.dart
└── 📂presentation
└───📂controller
│──comment_controller_test.dart
└──comment_controller_test.mocks.dart
📂lib
│───main.dart
│───di.dart
│───📂common
│ │───📂bloc
│ │ │──bloc_helper.dart
│ │ └──generic_bloc_state.dart
│ │───📂repository
│ │ └──repository_helper.dart
│ │───📂network
│ │ │──api_helper.dart
│ │ │──api_result.dart
│ │ │──api_result.freezed.dart
│ │ │──dio_client.dart
│ │ │──dio_exception.dart
│ │ └──dio_interceptor.dart
│ │───📂widget
│ │ │──date_time_picker.dart
│ │ │──drop_down.dart
│ │ │──empty_widget.dart
│ │ │──popup_menu.dart
│ │ │──spinkit_indicator.dart
│ │ └──text_input.dart
│ └───📂dialog
│ │──create_dialog.dart
│ │──delete_dialog.dart
│ │──progress_dialog.dart
│ └──retry_dialog.dart
│───📂core
│ │──api_config.dart
│ │──app_asset.dart
│ │──app_extension.dart
│ │──app_string.dart
│ │──app_style.dart
│ └──app_theme.dart
│
│───📂data
│ │───📂api
│ │ │───📂comment
│ │ │ └──comment_api.dart
│ │ │───📂post
│ │ │ └──post_api.dart
│ │ │───📂todo
│ │ │ └──todo_api.dart
│ │ └───📂user
│ │ └──user_api.dart
│ │
│ └───📂model
│ │───📂comment
│ │ │──comment.dart
│ │ └──comment.g.dart
│ │───📂post
│ │ │──post.dart
│ │ └──post.g.dart
│ │───📂todo
│ │ │──todo.dart
│ │ └──todo.g.dart
│ └───📂user
│ │──user.dart
│ └──user.g.dart
│
│───📂repository
│ │───📂comment
│ │ └──comment_repository.dart
│ │───📂post
│ │ └──post_repository.dart
│ │───📂todo
│ │ └──todo_repository.dart
│ └───📂user
│ └──user_repository.dart
│
│───📂view
│ │───📂post
│ │ └──📂screen
│ │ │──create_post_screen.dart
│ │ │──post_detail_screen.dart
│ │ └──post_list_screen.dart
│ │
│ │───📂todo
│ │ │──📂screen
│ │ │ └──todo_list_screen.dart
│ │ └──📂widget
│ │ │──circle_container.dart
│ │ └──todo_list_item.dart
│ │
│ └───📂user
│ │──📂screen
│ │ └──user_list_screen.dart
│ └──📂widget
│ └──status_container.dart
│
└───📂viewmodel
│───📂comment
│ └──📂bloc
│ └──comment_bloc.dart
│ └──comment_event.dart
│───📂post
│ └──📂bloc
│ └──post_bloc.dart
│ └──post_event.dart
│───📂todo
│ └──📂bloc
│ │──todo_bloc.dart
│ └──todo_event.dart
└───📂user
└──📂bloc
│──user_bloc.dart
└──user_event.dart
📂lib
│───main.dart
│───di.dart
│───📂common
│ │───📂cubit
│ │ │──generic_cubit.dart
│ │ └──generic_cubit_state.dart
│ │───📂repository
│ │ └──repository_helper.dart
│ │───📂network
│ │ │──api_helper.dart
│ │ │──api_result.dart
│ │ │──api_result.freezed.dart
│ │ │──dio_client.dart
│ │ │──dio_exception.dart
│ │ └──dio_interceptor.dart
│ │───📂widget
│ │ │──date_time_picker.dart
│ │ │──drop_down.dart
│ │ │──empty_widget.dart
│ │ │──popup_menu.dart
│ │ │──spinkit_indicator.dart
│ │ └──text_input.dart
│ └───📂dialog
│ │──create_dialog.dart
│ │──delete_dialog.dart
│ │──progress_dialog.dart
│ └──retry_dialog.dart
│───📂core
│ │──api_config.dart
│ │──app_asset.dart
│ │──app_extension.dart
│ │──app_string.dart
│ │──app_style.dart
│ └──app_theme.dart
│
│───📂data
│ │───📂api
│ │ │───📂comment
│ │ │ └──comment_api.dart
│ │ │───📂post
│ │ │ └──post_api.dart
│ │ │───📂todo
│ │ │ └──todo_api.dart
│ │ └───📂user
│ │ └──user_api.dart
│ │
│ └───📂model
│ │───📂comment
│ │ │──comment.dart
│ │ └──comment.g.dart
│ │───📂post
│ │ │──post.dart
│ │ └──post.g.dart
│ │───📂todo
│ │ │──todo.dart
│ │ └──todo.g.dart
│ └───📂user
│ │──user.dart
│ └──user.g.dart
│
│───📂repository
│ │───📂comment
│ │ └──comment_repository.dart
│ │───📂post
│ │ └──post_repository.dart
│ │───📂todo
│ │ └──todo_repository.dart
│ └───📂user
│ └──user_repository.dart
│
│───📂view
│ │───📂post
│ │ └──📂screen
│ │ │──create_post_screen.dart
│ │ │──post_detail_screen.dart
│ │ └──post_list_screen.dart
│ │
│ │───📂todo
│ │ │──📂screen
│ │ │ └──todo_list_screen.dart
│ │ └──📂widget
│ │ │──circle_container.dart
│ │ └──todo_list_item.dart
│ │
│ └───📂user
│ │──📂screen
│ │ └──user_list_screen.dart
│ └──📂widget
│ └──status_container.dart
│
└───📂viewmodel
│───📂comment
│ └──📂cubit
│ └──comment_cubit.dart
│───📂post
│ └──📂cubit
│ └──post_cubit.dart
│───📂todo
│ └──📂cubit
│ └──todo_cubit.dart
└───📂user
└──📂cubit
└──user_cubit.dart
📂lib
│───main.dart
│───di.dart
│───📂common
│ │───📂controller
│ │ └──base_controller.dart
│ │───📂repository
│ │ └──repository_helper.dart
│ │───📂network
│ │ │──api_helper.dart
│ │ │──api_result.dart
│ │ │──api_result.freezed.dart
│ │ │──dio_client.dart
│ │ │──dio_exception.dart
│ │ └──dio_interceptor.dart
│ │───📂widget
│ │ │──date_time_picker.dart
│ │ │──drop_down.dart
│ │ │──empty_widget.dart
│ │ │──popup_menu.dart
│ │ │──spinkit_indicator.dart
│ │ └──text_input.dart
│ └───📂dialog
│ │──create_dialog.dart
│ │──delete_dialog.dart
│ │──progress_dialog.dart
│ └──retry_dialog.dart
│───📂core
│ │──api_config.dart
│ │──app_asset.dart
│ │──app_extension.dart
│ │──app_string.dart
│ │──app_style.dart
│ └──app_theme.dart
│
│───📂data
│ │───📂api
│ │ │───📂comment
│ │ │ └──comment_api.dart
│ │ │───📂post
│ │ │ └──post_api.dart
│ │ │───📂todo
│ │ │ └──todo_api.dart
│ │ └───📂user
│ │ └──user_api.dart
│ │
│ └───📂model
│ │───📂comment
│ │ │──comment.dart
│ │ └──comment.g.dart
│ │───📂post
│ │ │──post.dart
│ │ └──post.g.dart
│ │───📂todo
│ │ │──todo.dart
│ │ └──todo.g.dart
│ └───📂user
│ │──user.dart
│ └──user.g.dart
│
│───📂repository
│ │───📂comment
│ │ └──comment_repository.dart
│ │───📂post
│ │ └──post_repository.dart
│ │───📂todo
│ │ └──todo_repository.dart
│ └───📂user
│ └──user_repository.dart
│
│───📂view
│ │───📂post
│ │ └──📂screen
│ │ │──create_post_screen.dart
│ │ │──post_detail_screen.dart
│ │ └──post_list_screen.dart
│ │
│ │───📂todo
│ │ │──📂screen
│ │ │ └──todo_list_screen.dart
│ │ └──📂widget
│ │ │──circle_container.dart
│ │ └──todo_list_item.dart
│ │
│ └───📂user
│ │──📂screen
│ │ └──user_list_screen.dart
│ └──📂widget
│ └──status_container.dart
│
└───📂viewmodel
│───📂comment
│ └──📂controller
│ └──comment_controller.dart
│───📂post
│ └──📂controller
│ └──post_controller.dart
│───📂todo
│ └──📂controller
│ └──todo_controller.dart
└───📂user
└──📂controller
└──user_controller.dart
📂lib
│───main.dart
│───📂common
│ │───📂cubit
│ │ │──generic_cubit.dart
│ │ └──generic_cubit_state.dart
│ │───📂network
│ │ │──api_base.dart
│ │ │──api_result.dart
│ │ │──api_result.freezed.dart
│ │ │──dio_client.dart
│ │ │──dio_exception.dart
│ │ └──dio_interceptor.dart
│ │───📂widget
│ │ │──date_time_picker.dart
│ │ │──drop_down.dart
│ │ │──empty_widget.dart
│ │ │──popup_menu.dart
│ │ │──spinkit_indicator.dart
│ │ └──text_input.dart
│ └───📂dialog
│ │──create_dialog.dart
│ │──delete_dialog.dart
│ │──progress_dialog.dart
│ └──retry_dialog.dart
│───📂core
│ │──api_config.dart
│ │──app_asset.dart
│ │──app_extension.dart
│ │──app_string.dart
│ │──app_style.dart
│ └──app_theme.dart
└───📂features
│───📂comment
│ │───📂cubit
│ │ └──comment_cubit.dart
│ └───📂data
│ │───📂model
│ │ │──comment.dart
│ │ └──comment.g.dart
│ └───📂provider
│ └──📂remote
│ └──comment_api.dart
│───📂post
│ │───📂cubit
│ │ └──post_cubit.dart
│ │───📂data
│ │ │───📂model
│ │ │ │──post.dart
│ │ │ └──post.g.dart
│ │ └───📂provider
│ │ └──📂remote
│ │ └──psot_api.dart
│ └───📂view
│ └──📂screen
│ │──create_post_screen.dart
│ │──post_detail_screen.dart
│ └──post_list_screen.dart
│───📂todo
│ │───📂cubit
│ │ └──todo_cubit.dart
│ │───📂data
│ │ │───📂model
│ │ │ │──todo.dart
│ │ │ └──todo.g.dart
│ │ └───📂provider
│ │ └──📂remote
│ │ └──todo_api.dart
│ └───📂view
│ │──📂screen
│ │ └──todo_list_screen.dart
│ └──📂widget
│ │──circle_container.dart
│ └──todo_list_item.dart
└───📂user
│───📂cubit
│ └──user_cubit.dart
│───📂data
│ │───📂model
│ │ │──user.dart
│ │ └──user.g.dart
│ └───📂provider
│ └──📂remote
│ └──user_api.dart
└───📂view
│──📂screen
│ └──user_list_screen.dart
└──📂widget
└──status_container.dart
📂lib
│───main.dart
│───📂common
│ │───📂bloc
│ │ │──bloc_helper.dart
│ │ └──generic_bloc_state.dart
│ │───📂network
│ │ │──api_base.dart
│ │ │──api_result.dart
│ │ │──api_result.freezed.dart
│ │ │──dio_client.dart
│ │ │──dio_exception.dart
│ │ └──dio_interceptor.dart
│ │───📂widget
│ │ │──date_time_picker.dart
│ │ │──drop_down.dart
│ │ │──empty_widget.dart
│ │ │──popup_menu.dart
│ │ │──spinkit_indicator.dart
│ │ └──text_input.dart
│ └───📂dialog
│ │──create_dialog.dart
│ │──delete_dialog.dart
│ │──progress_dialog.dart
│ └──retry_dialog.dart
│───📂core
│ │──api_config.dart
│ │──app_asset.dart
│ │──app_extension.dart
│ │──app_string.dart
│ │──app_style.dart
│ └──app_theme.dart
└───📂features
│───📂comment
│ │───📂bloc
│ │ │──comment_bloc.dart
│ │ └──comment_event.dart
│ └───📂data
│ │───📂model
│ │ │──comment.dart
│ │ └──comment.g.dart
│ └───📂provider
│ └──📂remote
│ └──comment_api.dart
│───📂post
│ │───📂bloc
│ │ └──post_bloc.dart
│ │ │──post_event.dart
│ │───📂data
│ │ │───📂model
│ │ │ │──post.dart
│ │ │ └──post.g.dart
│ │ └───📂provider
│ │ └──📂remote
│ │ └──psot_api.dart
│ └───📂view
│ └──📂screen
│ │──create_post_screen.dart
│ │──post_detail_screen.dart
│ └──post_list_screen.dart
│───📂todo
│ │───📂bloc
│ │ │──todo_bloc.dart
│ │ └──todo_event.dart
│ │───📂data
│ │ │───📂model
│ │ │ │──todo.dart
│ │ │ └──todo.g.dart
│ │ └───📂provider
│ │ └──📂remote
│ │ └──todo_api.dart
│ └───📂view
│ │──📂screen
│ │ └──todo_list_screen.dart
│ └──📂widget
│ │──circle_container.dart
│ └──todo_list_item.dart
└───📂user
│───📂bloc
│ │──user_bloc.dart
│ └──user_event.dart
│───📂data
│ │───📂model
│ │ │──user.dart
│ │ └──user.g.dart
│ └───📂provider
│ └──📂remote
│ └──user_api.dart
└───📂view
│──📂screen
│ └──user_list_screen.dart
└──📂widget
└──status_container.dart
📂lib
│───main.dart
│───📂common
│ │───📂controller
│ │ └──base_controller.dart
│ │───📂network
│ │ │──api_base.dart
│ │ │──dio_client.dart
│ │ │──dio_exception.dart
│ │ └──dio_interceptor.dart
│ │───📂widget
│ │ │──async_widget.dart
│ │ │──date_time_picker.dart
│ │ │──drop_down.dart
│ │ │──empty_widget.dart
│ │ │──popup_menu.dart
│ │ │──spinkit_indicator.dart
│ │ └──text_input.dart
│ └───📂dialog
│ │──create_dialog.dart
│ │──delete_dialog.dart
│ │──progress_dialog.dart
│ └──retry_dialog.dart
│───📂core
│ │──api_config.dart
│ │──app_asset.dart
│ │──app_extension.dart
│ │──app_string.dart
│ │──app_style.dart
│ └──app_theme.dart
└───📂features
│───📂comment
│ │───📂controller
│ │ └──comment_controller.dart
│ └───📂data
│ │───📂model
│ │ │──comment.dart
│ │ └──comment.g.dart
│ └───📂provider
│ └──📂remote
│ └──comment_api.dart
│───📂post
│ │───📂controller
│ │ └──post_controller.dart
│ │───📂data
│ │ │───📂model
│ │ │ │──post.dart
│ │ │ └──post.g.dart
│ │ └───📂provider
│ │ └──📂remote
│ │ └──psot_api.dart
│ └───📂view
│ └──📂screen
│ │──create_post_screen.dart
│ │──post_detail_screen.dart
│ └──post_list_screen.dart
│───📂todo
│ │───📂controller
│ │ └──todo_controller.dart
│ │───📂data
│ │ │───📂model
│ │ │ │──todo.dart
│ │ │ └──todo.g.dart
│ │ └───📂provider
│ │ └──📂remote
│ │ └──todo_api.dart
│ └───📂view
│ │──📂screen
│ │ └──todo_list_screen.dart
│ └──📂widget
│ │──circle_container.dart
│ └──todo_list_item.dart
└───📂user
│───📂controller
│ └──user_controller.dart
│───📂data
│ │───📂model
│ │ │──user.dart
│ │ └──user.g.dart
│ └───📂provider
│ └──📂remote
│ └──user_api.dart
└───📂view
│──📂screen
│ └──user_list_screen.dart
└──📂widget
└──status_container.dart
| Project Name | Stars |
|---|---|
| Japanese restaurant app | |
| Office furniture store app | |
| Ecommerce app |














