From cc45831b5922c453d79c6ceb2c16e6bf72cb5c18 Mon Sep 17 00:00:00 2001 From: m3mo Date: Wed, 4 Feb 2026 14:38:12 +0100 Subject: [PATCH] Add environment configuration with flavor support - Add AppConfig class for dev/prod environment settings - Create main_dev.dart and main_prod.dart entry points - Update datasources to use centralized API URL config - Support --dart-define=ENV for runtime configuration --- lib/core/config/app_config.dart | 55 +++++++++++++++++++ .../datasources/auth_remote_datasource.dart | 6 +- .../datasources/task_remote_datasource.dart | 6 +- lib/main.dart | 9 +++ lib/main_dev.dart | 21 +++++++ lib/main_prod.dart | 22 ++++++++ 6 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 lib/core/config/app_config.dart create mode 100644 lib/main_dev.dart create mode 100644 lib/main_prod.dart diff --git a/lib/core/config/app_config.dart b/lib/core/config/app_config.dart new file mode 100644 index 0000000..e5d670a --- /dev/null +++ b/lib/core/config/app_config.dart @@ -0,0 +1,55 @@ +/// Application configuration for different environments. +/// +/// This class provides environment-specific settings like API URLs +/// and logging levels, supporting both development and production builds. +class AppConfig { + final String apiBaseUrl; + final bool enableLogging; + final String environment; + + const AppConfig._({ + required this.apiBaseUrl, + required this.enableLogging, + required this.environment, + }); + + /// Development configuration (uses local backend) + static const AppConfig dev = AppConfig._( + apiBaseUrl: 'http://10.0.2.2:8000', // Android emulator localhost + enableLogging: true, + environment: 'development', + ); + + /// Production configuration (Linode VPS) + static const AppConfig prod = AppConfig._( + apiBaseUrl: 'http://172.104.152.69', + enableLogging: false, + environment: 'production', + ); + + /// Current active configuration (set at app startup) + static AppConfig _current = dev; + + /// Get the current configuration + static AppConfig get current => _current; + + /// Initialize configuration from dart-define or default to dev + static void initialize({String? environment}) { + const envFromDefine = String.fromEnvironment('ENV', defaultValue: 'dev'); + final env = environment ?? envFromDefine; + + switch (env) { + case 'prod': + case 'production': + _current = prod; + break; + case 'dev': + case 'development': + default: + _current = dev; + } + } + + @override + String toString() => 'AppConfig(env: $environment, api: $apiBaseUrl)'; +} diff --git a/lib/features/auth/data/datasources/auth_remote_datasource.dart b/lib/features/auth/data/datasources/auth_remote_datasource.dart index 3aec41c..68f06a2 100644 --- a/lib/features/auth/data/datasources/auth_remote_datasource.dart +++ b/lib/features/auth/data/datasources/auth_remote_datasource.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:http/http.dart' as http; +import '../../../../core/config/app_config.dart'; import '../../../../core/errors/exceptions.dart'; import '../../../../core/logging/app_logger.dart'; import '../models/token_model.dart'; @@ -29,10 +30,7 @@ class AuthRemoteDataSourceImpl implements AuthRemoteDataSource { final AppLogger logger; final http.Client _client; - static const String _baseUrl = String.fromEnvironment( - 'API_URL', - defaultValue: 'http://localhost:8000', - ); + String get _baseUrl => AppConfig.current.apiBaseUrl; AuthRemoteDataSourceImpl({ required this.logger, diff --git a/lib/features/tasks/data/datasources/task_remote_datasource.dart b/lib/features/tasks/data/datasources/task_remote_datasource.dart index e9fafae..df32283 100644 --- a/lib/features/tasks/data/datasources/task_remote_datasource.dart +++ b/lib/features/tasks/data/datasources/task_remote_datasource.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:http/http.dart' as http; +import '../../../../core/config/app_config.dart'; import '../../../../core/errors/exceptions.dart'; import '../../../../core/logging/app_logger.dart'; import '../models/task_model.dart'; @@ -21,10 +22,7 @@ class TaskRemoteDataSourceImpl implements TaskRemoteDataSource { final AppLogger logger; final http.Client _client; - static const String _baseUrl = String.fromEnvironment( - 'API_URL', - defaultValue: 'http://localhost:8000', - ); + String get _baseUrl => AppConfig.current.apiBaseUrl; TaskRemoteDataSourceImpl({ required this.logger, diff --git a/lib/main.dart b/lib/main.dart index 38a84d4..406c585 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,19 @@ import 'package:flutter/material.dart'; import 'app.dart'; +import 'core/config/app_config.dart'; import 'core/di/injection_container.dart' as di; +/// Default entry point (uses dart-define ENV or defaults to dev). +/// +/// Run with: flutter run +/// Or specify env: flutter run --dart-define=ENV=prod void main() async { WidgetsFlutterBinding.ensureInitialized(); + + // Initialize configuration from dart-define (defaults to dev) + AppConfig.initialize(); + await di.init(); runApp(const AgendaApp()); } diff --git a/lib/main_dev.dart b/lib/main_dev.dart new file mode 100644 index 0000000..8b32e68 --- /dev/null +++ b/lib/main_dev.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; + +import 'app.dart'; +import 'core/config/app_config.dart'; +import 'core/di/injection_container.dart' as di; + +/// Development entry point. +/// +/// Run with: flutter run -t lib/main_dev.dart +/// Or with explicit env: flutter run --dart-define=ENV=dev +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + + // Initialize development configuration + AppConfig.initialize(environment: 'dev'); + + // Initialize dependency injection + await di.init(); + + runApp(const AgendaApp()); +} diff --git a/lib/main_prod.dart b/lib/main_prod.dart new file mode 100644 index 0000000..a1cd575 --- /dev/null +++ b/lib/main_prod.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; + +import 'app.dart'; +import 'core/config/app_config.dart'; +import 'core/di/injection_container.dart' as di; + +/// Production entry point. +/// +/// Run with: flutter run -t lib/main_prod.dart --release +/// Or with explicit env: flutter run --dart-define=ENV=prod +/// Build APK: flutter build apk -t lib/main_prod.dart --release +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + + // Initialize production configuration + AppConfig.initialize(environment: 'prod'); + + // Initialize dependency injection + await di.init(); + + runApp(const AgendaApp()); +}