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
This commit is contained in:
m3mo 2026-02-04 14:38:12 +01:00
parent 1665070397
commit cc45831b59
6 changed files with 111 additions and 8 deletions

View File

@ -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)';
}

View File

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import '../../../../core/config/app_config.dart';
import '../../../../core/errors/exceptions.dart'; import '../../../../core/errors/exceptions.dart';
import '../../../../core/logging/app_logger.dart'; import '../../../../core/logging/app_logger.dart';
import '../models/token_model.dart'; import '../models/token_model.dart';
@ -29,10 +30,7 @@ class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
final AppLogger logger; final AppLogger logger;
final http.Client _client; final http.Client _client;
static const String _baseUrl = String.fromEnvironment( String get _baseUrl => AppConfig.current.apiBaseUrl;
'API_URL',
defaultValue: 'http://localhost:8000',
);
AuthRemoteDataSourceImpl({ AuthRemoteDataSourceImpl({
required this.logger, required this.logger,

View File

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import '../../../../core/config/app_config.dart';
import '../../../../core/errors/exceptions.dart'; import '../../../../core/errors/exceptions.dart';
import '../../../../core/logging/app_logger.dart'; import '../../../../core/logging/app_logger.dart';
import '../models/task_model.dart'; import '../models/task_model.dart';
@ -21,10 +22,7 @@ class TaskRemoteDataSourceImpl implements TaskRemoteDataSource {
final AppLogger logger; final AppLogger logger;
final http.Client _client; final http.Client _client;
static const String _baseUrl = String.fromEnvironment( String get _baseUrl => AppConfig.current.apiBaseUrl;
'API_URL',
defaultValue: 'http://localhost:8000',
);
TaskRemoteDataSourceImpl({ TaskRemoteDataSourceImpl({
required this.logger, required this.logger,

View File

@ -1,10 +1,19 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'app.dart'; import 'app.dart';
import 'core/config/app_config.dart';
import 'core/di/injection_container.dart' as di; 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 { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
// Initialize configuration from dart-define (defaults to dev)
AppConfig.initialize();
await di.init(); await di.init();
runApp(const AgendaApp()); runApp(const AgendaApp());
} }

21
lib/main_dev.dart Normal file
View File

@ -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());
}

22
lib/main_prod.dart Normal file
View File

@ -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());
}