├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .metadata
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── boilerplate
│ │ │ │ └── boilerplate
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-v21
│ │ │ └── launch_background.xml
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
├── icons
│ ├── icon_astronomy.svg
│ └── icon_image.svg
└── images
│ └── image_dog.png
├── integration_test
├── cases
│ └── app_route_test.dart
└── robot_tester
│ ├── app_robot.dart
│ ├── home_robot.dart
│ ├── intro_robot.dart
│ └── robot_tester_base.dart
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── lib
├── bootstrap.dart
├── configs
│ └── app_config.dart
├── core
│ ├── bloc_core
│ │ ├── bloc_observer.dart
│ │ ├── ui_status.dart
│ │ └── ui_status.freezed.dart
│ ├── dimens
│ │ └── app_dimens.dart
│ ├── exceptions
│ │ └── api_exception.dart
│ ├── keys
│ │ └── app_keys.dart
│ ├── spacings
│ │ └── app_spacing.dart
│ └── themes
│ │ └── app_themes.dart
├── data
│ └── repositories
│ │ └── dog_image_random
│ │ ├── local
│ │ ├── dog_image_local_repository.dart
│ │ └── dog_image_local_repository_impl.dart
│ │ └── remote
│ │ ├── dog_image_random_repository.dart
│ │ └── dog_image_random_repository_impl.dart
├── features
│ ├── app
│ │ ├── bloc
│ │ │ ├── app_bloc.dart
│ │ │ ├── app_bloc.freezed.dart
│ │ │ ├── app_event.dart
│ │ │ └── app_state.dart
│ │ └── view
│ │ │ ├── app.dart
│ │ │ └── app_director.dart
│ ├── demo
│ │ ├── bloc
│ │ │ ├── demo_bloc.dart
│ │ │ ├── demo_bloc.freezed.dart
│ │ │ ├── demo_event.dart
│ │ │ ├── demo_notification.dart
│ │ │ └── demo_state.dart
│ │ └── view
│ │ │ ├── assets_page.dart
│ │ │ └── images_from_db_page.dart
│ ├── dog_image_random
│ │ ├── bloc
│ │ │ ├── dog_image_random_bloc.dart
│ │ │ ├── dog_image_random_bloc.freezed.dart
│ │ │ ├── dog_image_random_event.dart
│ │ │ ├── dog_image_random_notification.dart
│ │ │ └── dog_image_random_state.dart
│ │ └── view
│ │ │ └── dog_image_random_page.dart
│ ├── home
│ │ └── home_page.dart
│ ├── intro
│ │ └── intro_page.dart
│ └── setting
│ │ └── setting_page.dart
├── injector
│ ├── injector.dart
│ └── modules
│ │ ├── bloc_module.dart
│ │ ├── database_module.dart
│ │ ├── dio_module.dart
│ │ ├── repository_module.dart
│ │ ├── rest_client_module.dart
│ │ └── service_module.dart
├── l10n
│ ├── intl_en.arb
│ └── intl_vi.arb
├── main.dart
├── router
│ └── app_router.dart
├── services
│ ├── app_service
│ │ ├── app_service.dart
│ │ └── app_service_impl.dart
│ ├── auth_service
│ │ ├── auth_service.dart
│ │ └── auth_service_impl.dart
│ ├── crashlytics_service
│ │ ├── crashlytics_service.dart
│ │ └── firebase_crashlytics_service.dart
│ ├── local_storage_service
│ │ ├── local_storage_service.dart
│ │ └── shared_preferences_service.dart
│ └── log_service
│ │ ├── debug_log_service.dart
│ │ └── log_service.dart
├── utils
│ └── mapper_utils.dart
└── widgets
│ ├── error_page.dart
│ ├── loading_page.dart
│ ├── splash_page.dart
│ └── widget_example.dart
├── packages
├── local_database
│ ├── .gitignore
│ ├── .metadata
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── lib
│ │ ├── local_database.dart
│ │ └── src
│ │ │ ├── app_database.dart
│ │ │ ├── app_database.g.dart
│ │ │ ├── app_database_manager.dart
│ │ │ ├── dao
│ │ │ ├── dao.dart
│ │ │ └── dog_image_dao.dart
│ │ │ └── entities
│ │ │ ├── dog_image_entity.dart
│ │ │ └── entities.dart
│ ├── pubspec.yaml
│ └── test
│ │ └── local_database_test.dart
└── rest_client
│ ├── .gitignore
│ ├── .metadata
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── lib
│ ├── rest_client.dart
│ └── src
│ │ ├── clients
│ │ ├── clients.dart
│ │ └── dog_api
│ │ │ ├── dog_api.dart
│ │ │ └── dog_api.g.dart
│ │ ├── converters
│ │ └── color_converter.dart
│ │ ├── models
│ │ ├── dog_image
│ │ │ ├── dog_image.dart
│ │ │ ├── dog_image.freezed.dart
│ │ │ └── dog_image.g.dart
│ │ └── models.dart
│ │ └── paging
│ │ ├── paging.dart
│ │ ├── paging.freezed.dart
│ │ └── paging.g.dart
│ ├── pubspec.yaml
│ └── test
│ └── rest_client_test.dart
├── pubspec.lock
├── pubspec.yaml
├── readme_attach
└── architecture.png
├── test
├── dependencies
│ ├── mock_dependencies.dart
│ └── mock_dependencies.mocks.dart
├── features
│ └── dog_image_random_bloc_test.dart
└── widget_test.dart
└── web
├── favicon.png
├── icons
├── Icon-192.png
├── Icon-512.png
├── Icon-maskable-192.png
└── Icon-maskable-512.png
├── index.html
└── manifest.json
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Flutter CI
2 |
3 | # This workflow is triggered on pull request to main branch.
4 |
5 | on:
6 | pull_request:
7 | branches:
8 | - main
9 |
10 | # on: push # Default will running for every branch.
11 |
12 | jobs:
13 | build_pipeline:
14 | runs-on: macos-latest
15 |
16 | strategy:
17 | matrix:
18 | api-level:
19 | - 29
20 |
21 | steps:
22 |
23 | # Setup Java environment in order to build the Android app.
24 | - uses: actions/checkout@v1
25 | - uses: actions/setup-java@v1
26 | with:
27 | java-version: '12.x'
28 |
29 | # Setup the flutter environment.
30 | - uses: subosito/flutter-action@v1
31 | with:
32 | channel: 'stable' # 'dev', 'alpha', default to: 'stable'
33 | flutter-version: '3.10.1' # you can also specify exact version of flutter
34 |
35 | # Get flutter dependencies.
36 | - run: flutter pub get
37 |
38 | - run: flutter pub upgrade
39 |
40 | - run: flutter pub run intl_utils:generate
41 |
42 | - run: flutter pub run build_runner build --delete-conflicting-outputs
43 |
44 | - name: local_database
45 | working-directory: ./packages/local_database
46 | run: flutter pub get && flutter pub upgrade && flutter pub run build_runner build --delete-conflicting-outputs
47 |
48 | - name: rest_client
49 | working-directory: ./packages/rest_client
50 | run: flutter pub get && flutter pub upgrade && flutter pub run build_runner build --delete-conflicting-outputs
51 |
52 | - run: flutter analyze
53 |
54 | - run: flutter test
55 |
56 |
57 | - name: Run integration tests
58 | uses: reactivecircus/android-emulator-runner@v2
59 | with:
60 | api-level: ${{ matrix.api-level }}
61 | arch: x86_64
62 | profile: Nexus 6
63 | script: flutter test integration_test --verbose
64 |
65 |
66 | - run: flutter build apk
67 |
68 | # Upload generated apk to the artifacts.
69 | - uses: actions/upload-artifact@v1
70 | with:
71 | name: release-apk
72 | path: build/app/outputs/apk/release/app-release.apk
73 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | **/ios/Flutter/.last_build_id
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 |
35 | # Symbolication related
36 | app.*.symbols
37 |
38 | # Obfuscation related
39 | app.*.map.json
40 |
41 | # Android Studio will place build artifacts here
42 | /android/app/debug
43 | /android/app/profile
44 | /android/app/release
45 |
46 | # Flutter gen code
47 | /lib/generated
48 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled.
5 |
6 | version:
7 | revision: eb6d86ee27deecba4a83536aa20f366a6044895c
8 | channel: stable
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
17 | base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
18 | - platform: android
19 | create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
20 | base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
21 | - platform: ios
22 | create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
23 | base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
24 | - platform: web
25 | create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
26 | base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c
27 |
28 | # User provided section
29 |
30 | # List of Local paths (relative to this file) that should be
31 | # ignored by the migrate tool.
32 | #
33 | # Files that are not part of the templates will be ignored by default.
34 | unmanaged_files:
35 | - 'lib/main.dart'
36 | - 'ios/Runner.xcodeproj/project.pbxproj'
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Trương Nhật Duy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |

5 |

6 |
7 |

8 |
9 |
10 |
11 |
12 | # Flutter Boilerplate Project
13 |
14 | A boilerplate project created in flutter using Bloc, Retrofit. Depend on code generation.
15 | ## Features
16 |
17 | * State management and examples
18 | * Api integration and examples
19 | * Local database and examples
20 | * Code generation
21 | * Local storage
22 | * Logging
23 | * Routing
24 | * Dependency Injection
25 | * Crashlytics template
26 | * DarkTheme
27 | * Multi languages
28 | * Unit tests
29 | * Integration test
30 | * Clean architecture
31 | * Flutter CI
32 |
33 | Some packages:
34 | - [Freezed](https://pub.dev/packages/freezed)
35 | - [Flutter Bloc](https://pub.dev/packages/flutter_bloc)
36 | - [Flutter gen](https://pub.dev/packages/flutter_gen)
37 | - [Retrofit](https://pub.dev/packages/retrofit)
38 | - [Dio](https://pub.dev/packages/retrofit)
39 | - [Bloc test](https://pub.dev/packages/bloc_test)
40 | - [Mockito](https://pub.dev/packages/mockito)
41 | - [Go router](https://pub.dev/packages/go_router)
42 | - [Dependency Injection](https://github.com/fluttercommunity/get_it)
43 | - [Logger](https://pub.dev/packages/logger)
44 | - [Floor](https://pub.dev/packages/floor)
45 | - [SharedPreferences](https://pub.dev/packages/shared_preferences)
46 |
47 |
48 | ## Getting Started
49 |
50 | The Boilerplate contains the minimal implementation required to create a new library or project. The repository code is preloaded with some basic components like basic app architecture, app theme, constants and required dependencies to create a new project. By using boiler plate code as standard initializer, we can have same patterns in all the projects that will inherit it. This will also help in reducing setup & development time by allowing you to use same code pattern and avoid re-writing from scratch.
51 |
52 | ### Up-Coming Features:
53 |
54 | * Handle multi bloc event in the same time by bloc concurrency example
55 | * Load more infinite list using bloc example
56 | * Authentication template
57 |
58 | ## Architecture
59 |
60 |
61 | ## How to Use
62 | **Step 1:**
63 |
64 | Fork, download or clone this repo by using the link below:
65 |
66 | ```
67 | https://github.com/zeref278/flutter_boilerplate.git
68 | ```
69 |
70 | **Step 2:**
71 | Go to project root and execute the following command in terminal to get the required dependencies and generate languages, freezed, flutter gen:
72 |
73 | ```cmd
74 | flutter pub get
75 | flutter pub run intl_utils:generate
76 | flutter pub run build_runner build --delete-conflicting-outputs
77 | ```
78 |
79 | **Step 3:**
80 | Go to `/packages/rest_client` and execute the following command in terminal to generate model and api client:
81 |
82 | ```cmd
83 | flutter pub get && flutter pub run build_runner build --delete-conflicting-outputs
84 | ```
85 |
86 | **Whenever change freezed file, assets, api**
87 |
88 | Run command
89 | ```cmd
90 | flutter pub get && flutter pub run build_runner build --delete-conflicting-outputs
91 | ```
92 |
93 | ## Folder structure
94 | ```
95 | flutter_boilerplate/
96 | |- assets/ (assets)
97 | |- lib/
98 | |- configs/ (flavor config)
99 | |- core/ (bloc observer, theme,...)
100 | |- data/ (repository)
101 | |- features/ (features page)
102 | |- generated/ (code generation includes localization and assets generation)
103 | |- injector/ (dependencies injector)
104 | |- l10n/ (localization resources
105 | |- router/ (routing)
106 | |- services/ (app services)
107 | |- utils/ (app utils)
108 | |- packages/
109 | |- rest_client/ (api client)
110 | |- local_database/ (local database)
111 | |- integration_test
112 | |- test/
113 | |- dependencies/ (mock dependencies)
114 | |- features/ (bloc test features)
115 |
116 | ```
117 |
118 | ## [Freezed](https://pub.dev/packages/freezed):
119 | ### Create a immutable Model with any features available
120 | - Define a `constructor` + the `properties`
121 | - Override `toString`, operator `==`, hashCode
122 | - Implement a `copyWith` method to clone the object
123 | - Handling `de/serialization`
124 | ### Example
125 | ```dart
126 | part 'dog_image.freezed.dart';
127 | part 'dog_image.g.dart';
128 |
129 | @Freezed(fromJson: true)
130 | class DogImage with _$DogImage {
131 | const factory DogImage({
132 | required String message,
133 | required String status,
134 | }) = _DogImage;
135 |
136 | factory DogImage.fromJson(Map json) =>
137 | _$DogImageFromJson(json);
138 | }
139 | ```
140 | ### Implement
141 | ```dart
142 | final DogImage dogImage = DogImage.fromJson(json);
143 | ///
144 | final DogImage dogImage = dogImage.copyWith(status: 'failed');
145 | /// Deep copy, equal operator ...
146 | ...
147 | ```
148 |
149 | ## [Retrofit]((https://pub.dev/packages/retrofit)):
150 | ### Create a api client by code generation, you do not need to implement each request manually
151 | ### Example
152 | ```dart
153 | part 'dog_api.g.dart';
154 |
155 | @RestApi()
156 | abstract class DogApiClient {
157 | factory DogApiClient(Dio dio, {String baseUrl}) = _DogApiClient;
158 |
159 | @GET('/breeds/image/random')
160 | Future getDogImageRandom();
161 | }
162 | ```
163 | Generate to
164 | ```dart
165 | ///
166 | @override
167 | Future getDogImageRandom() async {
168 | const _extra = {};
169 | final queryParameters = {};
170 | final _headers = {};
171 | final _data = {};
172 | final _result =
173 | await _dio.fetch