diff --git a/.gitignore b/.gitignore index 2226e7d..c87085f 100644 --- a/.gitignore +++ b/.gitignore @@ -121,8 +121,6 @@ app.*.symbols !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages !/dev/ci/**/Gemfile.lock -/app/env/ - /modules/common/.flutter-plugins /modules/common/.flutter-plugins-dependencies diff --git a/app/.gitignore b/app/.gitignore index e5bd2d0..f419504 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -125,9 +125,8 @@ app.*.symbols /env*.json # Environment and configuration files (contain sensitive data) -env/.env -env/.settings -env/env_*.json +../env/.env +../env/env_*.json .env .env.* *.env @@ -141,4 +140,4 @@ firebase-debug.log # Local development files local.properties -*.properties \ No newline at end of file +*.properties diff --git a/app/env/.env.example b/app/env/.env.example new file mode 100644 index 0000000..261c256 --- /dev/null +++ b/app/env/.env.example @@ -0,0 +1,13 @@ +# The .env file MUST be in .gitignore +# Delete this file after creating .env +# +# Each flavor (dev/qa/prod) uses the same .env file but reads +# different variables based on the suffix: +# - Development (main_dev.dart) → reads *_DEV variables +# - QA/Staging (main_qa.dart) → reads *_QA variables +# - Production (main.dart) → reads *_PROD variables + +API_URL_DEV=https://your-api-url-dev.com +API_URL_QA=https://your-api-url-qa.com +API_URL_PROD=https://your-api-url-prod.com + diff --git a/app/lib/main/env/env_config.dart b/app/lib/main/env/env_config.dart index 4154899..64e2e5a 100644 --- a/app/lib/main/env/env_config.dart +++ b/app/lib/main/env/env_config.dart @@ -1,9 +1,10 @@ +import 'package:domain/env/env_config.dart'; + enum Flavor { dev, qa, prod } class FlavorValues { - final String baseUrl; - FlavorValues({required this.baseUrl}); + FlavorValues(); } class FlavorConfig { @@ -22,6 +23,17 @@ class FlavorConfig { flavor.toString(), values, ); + switch(flavor) { + case Flavor.dev: + EnvConfig.env = EnvConfig.kDevEnv; + break; + case Flavor.qa: + EnvConfig.env = EnvConfig.kQaEnv; + break; + case Flavor.prod: + EnvConfig.env = EnvConfig.kProdEnv; + break; + } return _instance!; } @@ -34,4 +46,26 @@ class FlavorConfig { static bool isDevelopment() => instance.flavor == Flavor.dev; static bool isQA() => instance.flavor == Flavor.qa; + + /// Returns the environment file path (single .env file for all flavors) + /// + /// SETUP INSTRUCTIONS: + /// 1. Navigate to app/env/ directory + /// 2. Create a .env file (must be in .gitignore): + /// cp .env.example .env + /// 3. Add your environment variables with flavor suffixes: + /// API_URL_DEV=https://dev-api.example.com + /// API_URL_QA=https://qa-api.example.com + /// API_URL_PROD=https://api.example.com + /// 4. The active flavor determines which suffix is used (_DEV, _QA, _PROD) + /// 5. Access variables in domain/lib/env/env_config.dart using: + /// static String get apiUrl => dotenv.env['API_URL_$env']?.toString() ?? ''; + /// (The $env automatically appends DEV, QA, or PROD based on active flavor) + /// 6. Go to pubspec.yaml and add the following: + /// assets: + /// - env/.env + + static String getEnvFilePath() { + return 'env/.env.example'; + } } diff --git a/app/lib/main/env/main.dart b/app/lib/main/env/main.dart index 5741810..337e98d 100644 --- a/app/lib/main/env/main.dart +++ b/app/lib/main/env/main.dart @@ -1,13 +1,12 @@ import 'package:flutter/material.dart'; import 'package:app/main/env/env_config.dart'; import 'package:app/main/init.dart'; -import 'package:domain/env.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); FlavorConfig( flavor: Flavor.prod, - values: FlavorValues(baseUrl: EnvConfig.apiUrl), + values: FlavorValues(), ); //Add your firebase configuration here /*await Firebase.initializeApp( diff --git a/app/lib/main/env/main_dev.dart b/app/lib/main/env/main_dev.dart index 130904f..09e7e38 100644 --- a/app/lib/main/env/main_dev.dart +++ b/app/lib/main/env/main_dev.dart @@ -6,7 +6,7 @@ void main() async { WidgetsFlutterBinding.ensureInitialized(); FlavorConfig( flavor: Flavor.dev, - values: FlavorValues(baseUrl: "https://demo_dev/web_api.json"), + values: FlavorValues(), ); //Add your firebase configuration here /*await Firebase.initializeApp( diff --git a/app/lib/main/env/main_qa.dart b/app/lib/main/env/main_qa.dart index 47fc147..ad041d7 100644 --- a/app/lib/main/env/main_qa.dart +++ b/app/lib/main/env/main_qa.dart @@ -6,7 +6,7 @@ void main() async { WidgetsFlutterBinding.ensureInitialized(); FlavorConfig( flavor: Flavor.qa, - values: FlavorValues(baseUrl: "https://demo_qa/web_api.json"), + values: FlavorValues(), ); //Add your firebase configuration here /*await Firebase.initializeApp( diff --git a/app/lib/main/init.dart b/app/lib/main/init.dart index cd7eb36..2039053 100644 --- a/app/lib/main/init.dart +++ b/app/lib/main/init.dart @@ -5,9 +5,12 @@ import 'package:domain/init.dart'; import 'package:example_domain/init.dart'; import 'package:example_data/init.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:get_it/get_it.dart'; import 'package:url_strategy/url_strategy.dart'; +import 'env/env_config.dart'; + void init() async { WidgetsFlutterBinding.ensureInitialized(); await initialize(); @@ -18,11 +21,12 @@ void init() async { final getIt = GetIt.instance; Future initialize() async { + await dotenv.load(fileName: FlavorConfig.getEnvFilePath()); await CommonInit.initialize(getIt); await DataInit.initialize(getIt); await DomainInit.initialize(getIt); // Example Module init - await ExampleDomainInit.initialize(getIt); await ExampleDataInit.initialize(getIt); + await ExampleDomainInit.initialize(getIt); } diff --git a/app/lib/presentation/ui/custom/environment_selector.dart b/app/lib/presentation/ui/custom/environment_selector.dart new file mode 100644 index 0000000..abf77a3 --- /dev/null +++ b/app/lib/presentation/ui/custom/environment_selector.dart @@ -0,0 +1,50 @@ +import 'package:app/presentation/resources/resources.dart'; +import 'package:app/presentation/themes/local_theme.dart'; +import 'package:domain/env/env_config.dart'; +import 'package:domain/services/environment_service.dart'; +import 'package:flutter/material.dart'; + +import '../../../main/init.dart'; + +class EnvironmentSelector extends StatelessWidget { + EnvironmentSelector({ + super.key, + }); + + final EnvironmentService environmentService = getIt(); + + DropdownMenuItem _item( + String value, String label, TextStyle textStyle) => + DropdownMenuItem( + value: value, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: spacing.xs), + child: Text(label, style: textStyle), + ), + ); + + @override + Widget build(BuildContext context) { + final textStyle = + Theme.of(context).textTheme.bodyLarge?.copyWith(color: Theme.of(context).colorScheme.primary.v0); + + final items = >[ + _item(EnvConfig.kDevEnv, 'Development', textStyle!), + _item(EnvConfig.kQaEnv, 'QA', textStyle), + _item(EnvConfig.kProdEnv, 'Production', textStyle), + ]; + + return DropdownButtonFormField( + initialValue: EnvConfig.env, + style: textStyle, + decoration: InputDecoration( + labelText: 'Environment', + border: const OutlineInputBorder(), + prefixIcon: const Icon(Icons.settings), + labelStyle: textStyle, + ), + items: items, + onChanged: (value) => environmentService.setEnvironment(value!), + ); + } +} diff --git a/app/lib/presentation/ui/pages/login/login_page.dart b/app/lib/presentation/ui/pages/login/login_page.dart index 0f0336c..13de3a3 100644 --- a/app/lib/presentation/ui/pages/login/login_page.dart +++ b/app/lib/presentation/ui/pages/login/login_page.dart @@ -1,13 +1,17 @@ import 'package:app/main/init.dart'; +import 'package:app/presentation/resources/resources.dart'; import 'package:app/presentation/themes/app_themes.dart'; +import 'package:app/presentation/ui/custom/app_theme_switch.dart'; +import 'package:app/presentation/ui/custom/loading_screen.dart'; import 'package:common/core/resource.dart'; import 'package:domain/bloc/auth/auth_cubit.dart'; import 'package:domain/services/auth_service.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:app/presentation/ui/custom/app_theme_switch.dart'; -import 'package:app/presentation/ui/custom/loading_screen.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../custom/environment_selector.dart'; + class LoginPage extends StatelessWidget { AuthService get _authService => getIt(); @@ -21,12 +25,12 @@ class LoginPage extends StatelessWidget { appBar: AppBar(), backgroundColor: context.theme.colorScheme.surface, body: Padding( - padding: const EdgeInsets.all(16), + padding: EdgeInsets.all(spacing.m), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const AppThemeSwitch(), - const SizedBox(height: 16), + SizedBox(height: spacing.m), SizedBox( width: double.maxFinite, child: ElevatedButton( @@ -39,6 +43,10 @@ class LoginPage extends StatelessWidget { }, ), ), + SizedBox(height: spacing.xxxl), + if (kDebugMode) ...[ + EnvironmentSelector(), + ], ], ), ), diff --git a/app/pubspec.yaml b/app/pubspec.yaml index a6ff6c6..0c5c34a 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -39,6 +39,7 @@ dependencies: equatable: ^2.0.5 firebase_core: ^3.13.0 url_strategy: ^0.2.0 + flutter_dotenv: ^5.2.1 flutter_localizations: sdk: flutter domain: @@ -82,6 +83,8 @@ flutter: # Remove example assets. assets: - assets/images/ + # remove example suffix + - env/.env.example fonts: - family: Roboto Black fonts: diff --git a/modules/common/.flutter-plugins b/modules/common/.flutter-plugins deleted file mode 100644 index 40b8cd5..0000000 --- a/modules/common/.flutter-plugins +++ /dev/null @@ -1,6 +0,0 @@ -# This is a generated file; do not edit or check into version control. -package_info_plus=/Users/fabianvalencia/.pub-cache/hosted/pub.dev/package_info_plus-4.2.0/ -permission_handler=/Users/fabianvalencia/.pub-cache/hosted/pub.dev/permission_handler-10.4.5/ -permission_handler_android=/Users/fabianvalencia/.pub-cache/hosted/pub.dev/permission_handler_android-10.3.6/ -permission_handler_apple=/Users/fabianvalencia/.pub-cache/hosted/pub.dev/permission_handler_apple-9.1.4/ -permission_handler_windows=/Users/fabianvalencia/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.3/ diff --git a/modules/data/.flutter-plugins b/modules/data/.flutter-plugins deleted file mode 100644 index ae81242..0000000 --- a/modules/data/.flutter-plugins +++ /dev/null @@ -1,14 +0,0 @@ -# This is a generated file; do not edit or check into version control. -package_info_plus=/Users/usuario/.pub-cache/hosted/pub.dev/package_info_plus-4.1.0/ -path_provider_linux=/Users/usuario/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.0/ -path_provider_windows=/Users/usuario/.pub-cache/hosted/pub.dev/path_provider_windows-2.2.0/ -permission_handler=/Users/usuario/.pub-cache/hosted/pub.dev/permission_handler-10.4.3/ -permission_handler_android=/Users/usuario/.pub-cache/hosted/pub.dev/permission_handler_android-10.3.3/ -permission_handler_apple=/Users/usuario/.pub-cache/hosted/pub.dev/permission_handler_apple-9.1.4/ -permission_handler_windows=/Users/usuario/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.3/ -shared_preferences=/Users/usuario/.pub-cache/hosted/pub.dev/shared_preferences-2.2.0/ -shared_preferences_android=/Users/usuario/.pub-cache/hosted/pub.dev/shared_preferences_android-2.2.0/ -shared_preferences_foundation=/Users/usuario/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.3.3/ -shared_preferences_linux=/Users/usuario/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.3.0/ -shared_preferences_web=/Users/usuario/.pub-cache/hosted/pub.dev/shared_preferences_web-2.2.0/ -shared_preferences_windows=/Users/usuario/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.0/ diff --git a/modules/data/lib/init.dart b/modules/data/lib/init.dart index 93ac05b..00f3b99 100644 --- a/modules/data/lib/init.dart +++ b/modules/data/lib/init.dart @@ -6,9 +6,13 @@ import 'package:data/repositories/common_repository_impl.dart'; import 'package:dio/dio.dart'; import 'package:domain/repositories/auth_repository.dart'; import 'package:domain/repositories/common_repository.dart'; +import 'package:domain/services/environment_service.dart'; import 'package:get_it/get_it.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'network/config/environment_service_impl.dart'; +import 'network/interceptors/auth_token_interceptor.dart'; + class DataInit { static Future initialize(GetIt getIt) async { final pref = await SharedPreferences.getInstance(); @@ -16,14 +20,16 @@ class DataInit { getIt.registerSingleton(pref); getIt.registerSingleton(PreferencesImpl(getIt())); - //Network - getIt.registerLazySingleton(() => NetworkConfig.provideDio()); + // Network + getIt.registerLazySingleton(() => AuthTokenInterceptor(getIt())); + getIt.registerLazySingleton(() => NetworkConfig.provideDio(getIt())); + getIt.registerLazySingleton(() => EnvironmentServiceImpl(getIt())); - //Data Sources + // Data Sources - //Repositories + // Repositories getIt.registerLazySingleton( - () => AuthRepositoryImpl(getIt()), + () => AuthRepositoryImpl(getIt(),), ); getIt.registerLazySingleton( () => CommonRepositoryImpl(getIt()), diff --git a/modules/data/lib/network/config/environment_service_impl.dart b/modules/data/lib/network/config/environment_service_impl.dart new file mode 100644 index 0000000..f606681 --- /dev/null +++ b/modules/data/lib/network/config/environment_service_impl.dart @@ -0,0 +1,16 @@ +import 'package:data/network/config/network_config.dart'; +import 'package:dio/dio.dart'; +import 'package:domain/env/env_config.dart'; +import 'package:domain/services/environment_service.dart'; + +class EnvironmentServiceImpl extends EnvironmentService { + final Dio _dio; + + EnvironmentServiceImpl(this._dio); + + @override + void setEnvironment(String env) { + EnvConfig.env = env; + NetworkConfig.updateBaseUrl(_dio); + } +} diff --git a/modules/data/lib/network/config/network_config.dart b/modules/data/lib/network/config/network_config.dart index d4351e5..c130d50 100644 --- a/modules/data/lib/network/config/network_config.dart +++ b/modules/data/lib/network/config/network_config.dart @@ -1,11 +1,14 @@ import 'package:dio/dio.dart'; +import 'package:domain/env/env_config.dart'; +import 'package:flutter/foundation.dart'; +import '../interceptors/auth_token_interceptor.dart'; import 'network_constants.dart'; class NetworkConfig { - static Dio provideDio() { + static Dio provideDio(AuthTokenInterceptor? authTokenInterceptor) { final options = BaseOptions( - baseUrl: NetworkConstants.baseUrl, + baseUrl: EnvConfig.apiUrl, connectTimeout: const Duration( seconds: NetworkConstants.connectTimeout, ), @@ -13,6 +16,29 @@ class NetworkConfig { seconds: NetworkConstants.receiveTimeout, ), ); - return Dio(options); + + final dio = Dio(options); + + // Add debug logging only in debug mode + if (kDebugMode) { + dio.interceptors.add(LogInterceptor( + requestBody: true, + responseBody: true, + requestHeader: true, + responseHeader: true, + error: true, + logPrint: (object) => debugPrint(object.toString()), + )); + } + + if (authTokenInterceptor != null) { + dio.interceptors.add(authTokenInterceptor); + } + + return dio; + } + + static void updateBaseUrl(Dio dio) { + dio.options.baseUrl = EnvConfig.apiUrl; } } diff --git a/modules/data/lib/network/config/network_constants.dart b/modules/data/lib/network/config/network_constants.dart index 0105a30..c4a3581 100644 --- a/modules/data/lib/network/config/network_constants.dart +++ b/modules/data/lib/network/config/network_constants.dart @@ -4,4 +4,10 @@ class NetworkConstants { //static const baseUrl = String.fromEnvironment('API_URL', defaultValue: "NA"); static const productsPath = "/products"; static const baseUrl = "http://www.example.com"; // To get started: comment this and uncomment line 4 + static const tokenHeader = "token"; + static const unauthorizedStatusCode = 401; + static const forbiddenStatusCode = 403; + static const invalidStatusCode = 422; + static const contentTypeHeader = "Content-Type"; + static const applicationJsonContentType = "application/json"; } diff --git a/modules/data/lib/network/interceptors/auth_token_interceptor.dart b/modules/data/lib/network/interceptors/auth_token_interceptor.dart new file mode 100644 index 0000000..e073576 --- /dev/null +++ b/modules/data/lib/network/interceptors/auth_token_interceptor.dart @@ -0,0 +1,52 @@ +import 'package:dio/dio.dart'; + +import '../../preferences/preferences.dart'; +import '../config/network_constants.dart'; + +class AuthTokenInterceptor extends Interceptor { + final Preferences _preferences; + + AuthTokenInterceptor(this._preferences); + + @override + Future onRequest( + RequestOptions options, + RequestInterceptorHandler handler, + ) async { + try { + final token = _preferences.getToken(); + if (token != null && token.isNotEmpty) { + options.headers.addAll( + { + NetworkConstants.tokenHeader: token, + NetworkConstants.contentTypeHeader: + NetworkConstants.applicationJsonContentType, + }, + ); + } else { + await _clearCredentials(); + } + } catch (_) { + await _clearCredentials(); + } + return super.onRequest(options, handler); + } + + @override + void onError(DioException err, ErrorInterceptorHandler handler) { + try { + if (err.response?.statusCode == NetworkConstants.unauthorizedStatusCode || + err.response?.statusCode == NetworkConstants.forbiddenStatusCode || + err.response?.statusCode == NetworkConstants.invalidStatusCode) { + _clearCredentials(); + } + } catch (_) { + _clearCredentials(); + } + super.onError(err, handler); + } + + Future _clearCredentials() async { + _preferences.clear(); + } +} diff --git a/modules/data/lib/preferences/preferences.dart b/modules/data/lib/preferences/preferences.dart index aca06a8..267671b 100644 --- a/modules/data/lib/preferences/preferences.dart +++ b/modules/data/lib/preferences/preferences.dart @@ -14,4 +14,6 @@ abstract class Preferences { Future setAppTheme(String theme); Future setToken(String? token); + + Future clear(); } diff --git a/modules/data/lib/preferences/preferences_impl.dart b/modules/data/lib/preferences/preferences_impl.dart index 5a67559..8fff32f 100644 --- a/modules/data/lib/preferences/preferences_impl.dart +++ b/modules/data/lib/preferences/preferences_impl.dart @@ -43,4 +43,9 @@ class PreferencesImpl extends Preferences { if (token == null) return _pref.remove(_tokenKey); return _pref.setString(_tokenKey, token); } + + @override + Future clear() { + return _pref.clear(); + } } diff --git a/modules/data/lib/repositories/auth_repository_impl.dart b/modules/data/lib/repositories/auth_repository_impl.dart index 2c200d1..0f741ff 100644 --- a/modules/data/lib/repositories/auth_repository_impl.dart +++ b/modules/data/lib/repositories/auth_repository_impl.dart @@ -28,6 +28,6 @@ class AuthRepositoryImpl implements AuthRepository { @override Future logout() async { - _preferences.setToken(null); + _preferences.clear(); } } diff --git a/modules/domain/.flutter-plugins b/modules/domain/.flutter-plugins deleted file mode 100644 index 50f5e12..0000000 --- a/modules/domain/.flutter-plugins +++ /dev/null @@ -1,6 +0,0 @@ -# This is a generated file; do not edit or check into version control. -package_info_plus=/Users/usuario/.pub-cache/hosted/pub.dev/package_info_plus-4.1.0/ -permission_handler=/Users/usuario/.pub-cache/hosted/pub.dev/permission_handler-10.4.3/ -permission_handler_android=/Users/usuario/.pub-cache/hosted/pub.dev/permission_handler_android-10.3.3/ -permission_handler_apple=/Users/usuario/.pub-cache/hosted/pub.dev/permission_handler_apple-9.1.4/ -permission_handler_windows=/Users/usuario/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.3/ diff --git a/modules/domain/.flutter-plugins-dependencies b/modules/domain/.flutter-plugins-dependencies deleted file mode 100644 index 4f774ef..0000000 --- a/modules/domain/.flutter-plugins-dependencies +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"package_info_plus","path":"/Users/usuario/.pub-cache/hosted/pub.dev/package_info_plus-4.1.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/usuario/.pub-cache/hosted/pub.dev/permission_handler_apple-9.1.4/","native_build":true,"dependencies":[]}],"android":[{"name":"package_info_plus","path":"/Users/usuario/.pub-cache/hosted/pub.dev/package_info_plus-4.1.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/usuario/.pub-cache/hosted/pub.dev/permission_handler_android-10.3.3/","native_build":true,"dependencies":[]}],"macos":[{"name":"package_info_plus","path":"/Users/usuario/.pub-cache/hosted/pub.dev/package_info_plus-4.1.0/","native_build":true,"dependencies":[]}],"linux":[{"name":"package_info_plus","path":"/Users/usuario/.pub-cache/hosted/pub.dev/package_info_plus-4.1.0/","native_build":false,"dependencies":[]}],"windows":[{"name":"package_info_plus","path":"/Users/usuario/.pub-cache/hosted/pub.dev/package_info_plus-4.1.0/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/usuario/.pub-cache/hosted/pub.dev/permission_handler_windows-0.1.3/","native_build":true,"dependencies":[]}],"web":[{"name":"package_info_plus","path":"/Users/usuario/.pub-cache/hosted/pub.dev/package_info_plus-4.1.0/","dependencies":[]}]},"dependencyGraph":[{"name":"package_info_plus","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]}],"date_created":"2024-06-05 15:26:45.216002","version":"3.22.1"} \ No newline at end of file diff --git a/modules/domain/.gitignore b/modules/domain/.gitignore index f969096..62f0adc 100644 --- a/modules/domain/.gitignore +++ b/modules/domain/.gitignore @@ -29,4 +29,5 @@ migrate_working_dir/ .packages build/ .flutter-plugins-dependencies +.flutter-plugins /.flutter-plugins \ No newline at end of file diff --git a/modules/domain/lib/env.dart b/modules/domain/lib/env.dart deleted file mode 100644 index 4eff380..0000000 --- a/modules/domain/lib/env.dart +++ /dev/null @@ -1,3 +0,0 @@ -class EnvConfig { - static const apiUrl = "https://dummyjson.com"; //String.fromEnvironment('API_URL', defaultValue: "http://movies.com"); -} diff --git a/modules/domain/lib/env/env_config.dart b/modules/domain/lib/env/env_config.dart new file mode 100644 index 0000000..e6e83f6 --- /dev/null +++ b/modules/domain/lib/env/env_config.dart @@ -0,0 +1,13 @@ +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +class EnvConfig { + static const String kDevEnv = "DEV"; + static const String kProdEnv = "PROD"; + static const String kQaEnv = "QA"; + + static String env = kDevEnv; + + static String get envConfigFile => 'env/.env.example'; + + static String get apiUrl => dotenv.env['API_URL_$env']?.toString() ?? ''; +} diff --git a/modules/domain/lib/services/environment_service.dart b/modules/domain/lib/services/environment_service.dart new file mode 100644 index 0000000..cc57793 --- /dev/null +++ b/modules/domain/lib/services/environment_service.dart @@ -0,0 +1,3 @@ +abstract class EnvironmentService { + void setEnvironment(String env); +} diff --git a/modules/domain/pubspec.yaml b/modules/domain/pubspec.yaml index d8f2535..9da14e6 100644 --- a/modules/domain/pubspec.yaml +++ b/modules/domain/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: get_it: ^7.6.0 equatable: ^2.0.5 url_strategy: ^0.2.0 + flutter_dotenv: ^5.2.1 flutter_localizations: sdk: flutter common: