generated from nimblehq/git-template
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #35 from nimblehq/release/0.4.0
Release v0.4.0 (6)
- Loading branch information
Showing
23 changed files
with
478 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
SECRET= | ||
REST_API_ENDPOINT= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,23 +9,35 @@ Clone the repository | |
`git clone [email protected]:nimblehq/flutter_templates.git` | ||
|
||
## Prerequisite | ||
|
||
- Flutter 2.2 | ||
- Flutter version manager (recommend): [fvm](https://fvm.app/) | ||
|
||
## Getting Started | ||
|
||
- Create these env files in the root directory according to the flavors and add the required environment variables into them. The example environment variable is in `.env.sample`. | ||
### Setup | ||
|
||
- Create these `.env` files in the root directory according to the flavors and add the required | ||
environment variables into them. The example environment variable is in `.env.sample`. | ||
|
||
- Staging: `.env.staging` | ||
|
||
- Production: `.env` | ||
|
||
- Run code generator | ||
|
||
- `$ fvm flutter packages pub run build_runner build --delete-conflicting-outputs` | ||
|
||
### Run | ||
|
||
- Run the app with the desire app flavor: | ||
|
||
- Staging: `$ fvm flutter run --flavor staging` | ||
|
||
- Production: `$ fvm flutter run --flavor production` | ||
|
||
### Test | ||
|
||
- Run unit testing: | ||
|
||
- `$ fvm flutter test .` | ||
|
@@ -38,10 +50,6 @@ Clone the repository | |
|
||
`$ fvm flutter drive --driver=test_driver/integration_test.dart --target=integration_test/my_home_page_test.dart --flavor staging` | ||
|
||
- Generate assets folder | ||
|
||
- `$ fvm flutter packages pub run build_runner build --delete-conflicting-outputs` | ||
|
||
## Use the template | ||
|
||
### Setup a new project | ||
|
@@ -54,7 +62,15 @@ Clone the repository | |
|
||
- Re-fetch the project: `$ fvm flutter pub get` | ||
|
||
- The project uses the package name, the app name and the project name of the template if `PACKAGE_NAME`, `APP_NAME` and `PROJECT_NAME` aren't specified. | ||
- Parameters detail: | ||
|
||
| Parameter name | Is mandatory | Description | | ||
| :------------- | :----------: | :------------------------------------------------------------------------------ | | ||
| PACKAGE_NAME | Yes | The application package name. The naming convention follows `com.your.package` | | ||
| PROJECT_NAME | Yes | The application project name. The naming convention follows `your_project_name` | | ||
| APP_NAME | Yes | The application name. | | ||
| APP_VERSION | No | The app version that is set when initialize the project. Default is `0.1.0` | | ||
| BUILD_NUMBER | No | The build number that is set when initialize the project. Default is `1` | | ||
|
||
- For more supporting commands, run: | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,14 @@ | ||
import 'package:dio/dio.dart'; | ||
import 'package:flutter_templates/model/response/user_response.dart'; | ||
import 'package:retrofit/retrofit.dart'; | ||
|
||
part 'api_service.g.dart'; | ||
|
||
@RestApi() | ||
abstract class ApiService { | ||
Future<UserResponse> getProfile(); | ||
factory ApiService(Dio dio, {String baseUrl}) = _ApiService; | ||
|
||
// TODO add API endpoint | ||
@GET('users') | ||
Future<List<UserResponse>> getUsers(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import 'dart:io'; | ||
|
||
import 'package:dio/dio.dart'; | ||
import 'package:freezed_annotation/freezed_annotation.dart'; | ||
|
||
part 'network_exceptions.freezed.dart'; | ||
|
||
@freezed | ||
class NetworkExceptions with _$NetworkExceptions { | ||
const factory NetworkExceptions.requestCancelled() = RequestCancelled; | ||
|
||
const factory NetworkExceptions.unauthorisedRequest() = UnauthorisedRequest; | ||
|
||
const factory NetworkExceptions.badRequest() = BadRequest; | ||
|
||
const factory NetworkExceptions.notFound(String reason) = NotFound; | ||
|
||
const factory NetworkExceptions.methodNotAllowed() = MethodNotAllowed; | ||
|
||
const factory NetworkExceptions.notAcceptable() = NotAcceptable; | ||
|
||
const factory NetworkExceptions.requestTimeout() = RequestTimeout; | ||
|
||
const factory NetworkExceptions.receiveTimeout() = ReceiveTimeout; | ||
|
||
const factory NetworkExceptions.sendTimeout() = SendTimeout; | ||
|
||
const factory NetworkExceptions.conflict() = Conflict; | ||
|
||
const factory NetworkExceptions.internalServerError() = InternalServerError; | ||
|
||
const factory NetworkExceptions.notImplemented() = NotImplemented; | ||
|
||
const factory NetworkExceptions.serviceUnavailable() = ServiceUnavailable; | ||
|
||
const factory NetworkExceptions.noInternetConnection() = NoInternetConnection; | ||
|
||
const factory NetworkExceptions.formatException() = FormatException; | ||
|
||
const factory NetworkExceptions.unableToProcess() = UnableToProcess; | ||
|
||
const factory NetworkExceptions.defaultError(String error) = DefaultError; | ||
|
||
const factory NetworkExceptions.unexpectedError() = UnexpectedError; | ||
|
||
static NetworkExceptions fromDioException(error) { | ||
if (error is Exception) { | ||
try { | ||
NetworkExceptions networkExceptions; | ||
if (error is DioError) { | ||
switch (error.type) { | ||
case DioErrorType.cancel: | ||
networkExceptions = NetworkExceptions.requestCancelled(); | ||
break; | ||
case DioErrorType.connectTimeout: | ||
networkExceptions = NetworkExceptions.requestTimeout(); | ||
break; | ||
case DioErrorType.other: | ||
networkExceptions = NetworkExceptions.noInternetConnection(); | ||
break; | ||
case DioErrorType.receiveTimeout: | ||
networkExceptions = NetworkExceptions.receiveTimeout(); | ||
break; | ||
case DioErrorType.sendTimeout: | ||
networkExceptions = NetworkExceptions.sendTimeout(); | ||
break; | ||
case DioErrorType.response: | ||
switch (error.response?.statusCode) { | ||
case 400: | ||
networkExceptions = NetworkExceptions.badRequest(); | ||
break; | ||
case 401: | ||
networkExceptions = NetworkExceptions.unauthorisedRequest(); | ||
break; | ||
case 403: | ||
networkExceptions = NetworkExceptions.unauthorisedRequest(); | ||
break; | ||
case 404: | ||
networkExceptions = NetworkExceptions.notFound("Not found"); | ||
break; | ||
case 409: | ||
networkExceptions = NetworkExceptions.conflict(); | ||
break; | ||
case 408: | ||
networkExceptions = NetworkExceptions.requestTimeout(); | ||
break; | ||
case 500: | ||
networkExceptions = NetworkExceptions.internalServerError(); | ||
break; | ||
case 503: | ||
networkExceptions = NetworkExceptions.serviceUnavailable(); | ||
break; | ||
default: | ||
var responseCode = error.response?.statusCode; | ||
networkExceptions = NetworkExceptions.defaultError( | ||
"Received invalid status code: $responseCode", | ||
); | ||
} | ||
break; | ||
} | ||
} else if (error is SocketException) { | ||
networkExceptions = NetworkExceptions.noInternetConnection(); | ||
} else { | ||
networkExceptions = NetworkExceptions.unexpectedError(); | ||
} | ||
return networkExceptions; | ||
} on FormatException catch (_) { | ||
return NetworkExceptions.formatException(); | ||
} catch (_) { | ||
return NetworkExceptions.unexpectedError(); | ||
} | ||
} else { | ||
if (error.toString().contains("is not a subtype of")) { | ||
return NetworkExceptions.unableToProcess(); | ||
} else { | ||
return NetworkExceptions.unexpectedError(); | ||
} | ||
} | ||
} | ||
|
||
static String getErrorMessage(NetworkExceptions networkExceptions) { | ||
var errorMessage = ""; | ||
networkExceptions.when(notImplemented: () { | ||
errorMessage = "Not Implemented"; | ||
}, requestCancelled: () { | ||
errorMessage = "Request Cancelled"; | ||
}, internalServerError: () { | ||
errorMessage = "Internal Server Error"; | ||
}, notFound: (String reason) { | ||
errorMessage = reason; | ||
}, serviceUnavailable: () { | ||
errorMessage = "Service unavailable"; | ||
}, methodNotAllowed: () { | ||
errorMessage = "Method not allowed"; | ||
}, badRequest: () { | ||
errorMessage = "Bad request"; | ||
}, unauthorisedRequest: () { | ||
errorMessage = "Unauthorised request"; | ||
}, unexpectedError: () { | ||
errorMessage = "Unexpected error occurred"; | ||
}, requestTimeout: () { | ||
errorMessage = "Connection request timeout"; | ||
}, noInternetConnection: () { | ||
errorMessage = "No internet connection"; | ||
}, conflict: () { | ||
errorMessage = "Error due to a conflict"; | ||
}, sendTimeout: () { | ||
errorMessage = "Send timeout in connection with API server"; | ||
}, receiveTimeout: () { | ||
errorMessage = "Receive timeout in connection with API server"; | ||
}, unableToProcess: () { | ||
errorMessage = "Unable to process the data"; | ||
}, defaultError: (String error) { | ||
errorMessage = error; | ||
}, formatException: () { | ||
errorMessage = "Unexpected error occurred"; | ||
}, notAcceptable: () { | ||
errorMessage = "Not acceptable"; | ||
}); | ||
return errorMessage; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import 'package:dio/dio.dart'; | ||
|
||
class AppInterceptor extends Interceptor { | ||
bool _requireAuthenticate; | ||
|
||
AppInterceptor(this._requireAuthenticate); | ||
|
||
@override | ||
Future onRequest( | ||
RequestOptions options, RequestInterceptorHandler handler) async { | ||
if (_requireAuthenticate) { | ||
// TODO header authorization here | ||
// options.headers | ||
// .putIfAbsent(HEADER_AUTHORIZATION, () => ""); | ||
} | ||
return super.onRequest(options, handler); | ||
} | ||
} |
Oops, something went wrong.