Flutter Boilerplate containing pre initialised services and following standardised protocol for code quality.
Maintained by - Abhijeet Tripathi
| Feature | Availability | 
|---|---|
| Ready to use | ✅ | 
| MVVM based | ✅ | 
| Network services | ✅ | 
| Using Providers | ✅ | 
| Modular | ✅ | 
| Assets and custom Fonts | ✅ | 
| Embedded custom URL screen | ✅ | 
- Clone this repo
    git clone https://github.com/joshsoftware/flutter-boilerplate.git- 
Rename "flutter-boilerplate" folder to your "project_name" 
- 
Open folder in Android Studio 
- 
Open project's pubspec.yaml and change // This is Flutter level project name do not consider this as bundle id or application id - "name: flutter_mvvm_boilerplate" to "name: project_name"
- "description: Ready to use flutter boiler plate" to "description: Your project description"
 
- 
In Android Studio's Terminal run 
flutter pub getNote: You'll start getting errors in all your files it's because we've changed the flutter package name and imports are still directing to old package name.
- 
Right click on "lib" folder and click "Replace in path" and replace "flutter_mvvm_boilerplate" to "project_name" (same as you used in pubspec.yaml) click "Replace All". Note: Most of your errors will go away if not just close and reopen Android Studio once. 
- 
Change Application name and ID: Open terminal tab in Android Studio and run following commands. 
• This will install package rename tool
flutter pub global activate rename • This will rename your Application name
flutter pub global run rename --appname "Project Name"• This will rename your Application ID/Bundle ID
flutter pub global run rename --bundleId com.companyname.projectname- Add and register project specific assets and you're ready to go.
Description
Maintainability is achieved by distributing type of Constant Data into specific category. Important constants files are
- 
api_constants.dart - Contains base URL and all the end points that application is going to use.
 
- 
app_constants.dart - Contains maintenance flag for changing Production and Staging Environments
- Also contains app related constants
 
- 
singleton_constants.dart - This is a Singleton class for general purpose data sharing over the app User object, token etc.
 
- 
Other constants files are self explanatory 
Description
Base Response Model is designed for productive API integration. This model can be modified according to Project's API structure.
File name
- response_data_model.dart
Keys to change
- Data
- Error and Message
- okAndContainsData
Based on your API Structure change the 'data' key to specified key where all your response's data will be delivered. Example: For given API structure
{
'data': [
  {
    'name': 'Abhijeet Tripathi',
    'mail': '[email protected]'
  }
{
    'name': 'Shekhar Sahu',
    'mail': '[email protected]'
  }
],
'message' : 'Data fetched',
'error' : 'None till now'
}the keys will be..
data: parsedJson['data'] != null ? parsedJson['data'] : null,
okAndContainsData: (response.statusCode == 200 ) && (parsedJson['data'] != null),
message: parsedJson['message'] != null ? parsedJson['message'] : "",Though this model is null safe but it's not safe from parsing errors.
Always cross checks key names and hierarchy of them.
Description
Networking layer is preinitialised with following features.
- Network connection check
- Common loader
- Common Error and Success Message
- Prettyfied Logs for easy debugging.
Responsible files
- api_helper.dart
- api_service.dart
- api_constants.dart
- network_check.dart
- pretty_json_print.dart
Things to change
In api_helper.dart change the following as per your project needs.
- DEFAULT_TIMEOUT this is a top level variable denotes time out seconds. Default is 45.
- _getHeaders this is Header generator for API call change as per required.
- _handleError this is error handler for all REST calls you can handle unauthorised logout and error alert directly from here.
Usage example
- Declare end point you want consume in api_constants.dart in given format.
static const String LOGIN = "/api/login";- Create URI with base URL and end point in your function
//  baseURL here is Getter of String type that returns your base URL from
//  api_constants.dart and is directly accesibile.
Uri _loginUri = Uri.parse(baseURL + ApiConstants.LOGIN);- Use ApiHelper class it contains plug and play REST callers
- ApiHelper have 2 types of caller
- Plug and Play This requires BuildContext and contains common loader and alert dialog built in
- BG : This doesn't requires context can be called in Background but it doesn't contains UI elements everything will be handled by developer.
 
Map map =  { "email": "[email protected]","password": "cityslicka" }
// If showConnectivityError is set to false will Throw NoNetworkException in case of no connectivity.
// showConnectivityError: false allows developer to handle no connectivity exception manually.
// Plug and Play with common loader and dialog
ResponseData responseData =  
   await ApiHelper().postRequest(context, _loginUri, map,  
         useAuth: false, showLoader: true, responseName: "Login",
         showLog: true, showError: true, showConnectivityError: true); 
// Background callers without loader and dialog
// Throws NoNetworkException in case of no nonnectivity.
try {  
 ResponseData responseData =  
   await ApiHelper().postRequestBG(_loginUri,map,useAuth: false,showLog: true);
} on NoNetworkException {  
     print("Please Check Internet Connection");  
     //Handle error on UI if using BG callers  
}
- Check response and consume.
if (responseData.okAndContainsData ) {
   print(responseData.data['message'])
   // Do success stuff here.
}else if(responseData.statusCode == 500){
   // Handle 500.
}else{
   // Handle everthing else.
}
Description
Navigation is straight forward
Responsible file
- navigation_helper.dart
- Always provide Navigation TAG - All views have their own specific tag
static const String TAG = "/LoginView";These tags help to easily access and switch to views
- Register path in routes - in main.dart register paths to their respective view.
routes: {  
LoginView.TAG: (context) => NavigationHelper.getLoginViewWithProvider(),  
},- Keep Function naming standard
///Naming Standard:  
///Fun that gives View with provider             - getViewNameWithProvider()  
///Fun that pushes View                          - gotoViewName() 
///Fun that return Data				 - gotoViewNameWithResult()
///Fun(Data data) that pushes View with data     - gotoViewNameWithData(data)  
///Fun that clears stack and pushes View         - clearAndGotoViewName()