From 940f73809c34338328951a7d2538cd0818b194a6 Mon Sep 17 00:00:00 2001 From: Patryk Hegenberg Date: Sun, 4 Jan 2026 18:54:24 +0100 Subject: [PATCH] feat: add more security enviroment variable based settings --- lib/main.dart | 10 ++ lib/src/core/constants/app_constants.dart | 30 +++++- lib/src/core/debug/debug_config_screen.dart | 96 +++++++++++++++++++ .../presentation/screens/hub_screen.dart | 13 +++ 4 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 lib/src/core/debug/debug_config_screen.dart diff --git a/lib/main.dart b/lib/main.dart index 2c98f4c..dc9f9da 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,10 +3,20 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'src/app.dart'; import 'src/shared/data/local/app_database.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); + try { + await dotenv.load(fileName: '.env'); + debugPrint('✅ Environment loaded: ${dotenv.env['ENVIRONMENT']}'); + debugPrint('✅ API URL: ${dotenv.env['API_BASE_URL']}'); + } catch (e) { + debugPrint('⚠️ Could not load .env file: $e'); + debugPrint('⚠️ Using default production values'); + } + await SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, diff --git a/lib/src/core/constants/app_constants.dart b/lib/src/core/constants/app_constants.dart index 21d0838..977d621 100644 --- a/lib/src/core/constants/app_constants.dart +++ b/lib/src/core/constants/app_constants.dart @@ -1,10 +1,36 @@ import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; class AppConstants { + // ✅ API Configuration aus Environment + static String get apiBaseUrl => + dotenv.env['API_BASE_URL'] ?? 'https://slift.patanix.de'; + + static String get apiVersion => dotenv.env['API_VERSION'] ?? 'v1'; + + static String get environment => dotenv.env['ENVIRONMENT'] ?? 'production'; + + static bool get isDebugMode => + dotenv.env['DEBUG_MODE']?.toLowerCase() == 'true'; + + // ✅ Helper Getter + static bool get isDevelopment => environment == 'development'; + static bool get isProduction => environment == 'production'; + + // Debug Info + static void printConfig() { + debugPrint('═══════════════════════════════════'); + debugPrint('🔧 APP CONFIGURATION'); + debugPrint('Environment: $environment'); + debugPrint('API Base URL: $apiBaseUrl'); + debugPrint('API Version: $apiVersion'); + debugPrint('Debug Mode: $isDebugMode'); + debugPrint('═══════════════════════════════════'); + } // API Configuration // static const String apiBaseUrl = 'http://10.0.2.2:8090'; // Android emulator - static const String apiBaseUrl = 'https://slift.patanix.de'; - static const String apiVersion = 'v1'; + // static const String apiBaseUrl = 'https://slift.patanix.de'; + // static const String apiVersion = 'v1'; // Wendler 5/3/1 Constants static const double trainingMaxPercentage = 0.9; diff --git a/lib/src/core/debug/debug_config_screen.dart b/lib/src/core/debug/debug_config_screen.dart new file mode 100644 index 0000000..c938977 --- /dev/null +++ b/lib/src/core/debug/debug_config_screen.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +import '../constants/app_constants.dart'; +import '../theme/app_theme.dart'; + +class DebugConfigScreen extends StatelessWidget { + const DebugConfigScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('🔧 Configuration'), + ), + body: ListView( + padding: const EdgeInsets.all(16), + children: [ + _buildSection( + 'Environment', + [ + _buildRow('Environment', AppConstants.environment), + _buildRow('Debug Mode', AppConstants.isDebugMode.toString()), + _buildRow( + 'Is Development', AppConstants.isDevelopment.toString()), + _buildRow('Is Production', AppConstants.isProduction.toString()), + ], + ), + const SizedBox(height: 16), + _buildSection( + 'API Configuration', + [ + _buildRow('Base URL', AppConstants.apiBaseUrl), + _buildRow('API Version', AppConstants.apiVersion), + ], + ), + const SizedBox(height: 16), + _buildSection( + 'All Environment Variables', + dotenv.env.entries.map((e) => _buildRow(e.key, e.value)).toList(), + ), + ], + ), + ); + } + + Widget _buildSection(String title, List children) { + return Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: AppTheme.primaryColor, + ), + ), + const Divider(), + ...children, + ], + ), + ), + ); + } + + Widget _buildRow(String key, String value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 120, + child: Text( + key, + style: const TextStyle( + fontWeight: FontWeight.bold, + color: Colors.grey, + ), + ), + ), + Expanded( + child: Text( + value, + style: const TextStyle(color: Colors.white), + ), + ), + ], + ), + ); + } +} diff --git a/lib/src/features/dashboard/presentation/screens/hub_screen.dart b/lib/src/features/dashboard/presentation/screens/hub_screen.dart index f1fd278..99f30a9 100644 --- a/lib/src/features/dashboard/presentation/screens/hub_screen.dart +++ b/lib/src/features/dashboard/presentation/screens/hub_screen.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; +import '../../../../core/constants/app_constants.dart'; +import '../../../../core/debug/debug_config_screen.dart'; import '../../../../core/theme/app_theme.dart'; import '../../../../shared/data/local/app_database.dart'; import '../../../../shared/data/repositories/user_repository.dart'; @@ -292,6 +294,17 @@ class _HubScreenState extends ConsumerState { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + if (AppConstants.isDevelopment) + IconButton( + icon: const Icon(Icons.settings), + onPressed: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const DebugConfigScreen(), + ), + ), + ), IconButton( icon: const Icon(Icons.person_outline), onPressed: () => context.go('/profile'),