import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_application_1/calculator.dart'; import 'package:flutter_application_1/enums.dart'; import 'package:flutter_application_1/utils.dart'; import 'package:flutter_application_1/widgets/input_widget.dart'; import 'package:flutter_application_1/widgets/interval_widget.dart'; import 'package:flutter_application_1/widgets/result_widget.dart'; import 'package:flutter_application_1/widgets/error_widget.dart'; import 'package:flutter_application_1/widgets/language_switcher_widget.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override MyAppState createState() => MyAppState(); } class MyAppState extends State { Locale _locale = const Locale('de'); // Standard-Locale void _changeLanguage(Locale locale) { setState(() { _locale = locale; }); } @override Widget build(BuildContext context) { return MaterialApp( title: 'Compound interest calculator', localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [ Locale('en'), // English Locale('de'), // Deutsch ], locale: _locale, theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: CupertinoColors.white, background: CupertinoColors.white), useMaterial3: true, ), home: MyHomePage( title: 'Compound interest calculator', onLocaleChanged: _changeLanguage, // Übergibt die Sprachwechsel-Funktion an die Startseite ), debugShowCheckedModeBanner: false, ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title, required this.onLocaleChanged}); final String title; final Function(Locale) onLocaleChanged; @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { // Controller und Fokus-Knoten für die Eingabefelder final TextEditingController _initialCapitalController = TextEditingController(); final TextEditingController _monthlySavingsRateController = TextEditingController(); final TextEditingController _interestRateController = TextEditingController(); final TextEditingController _timeController = TextEditingController(); final FocusNode _initialCapitalFocusNode = FocusNode(); final FocusNode _monthlySavingsRateFocusNode = FocusNode(); final FocusNode _interestRateFocusNode = FocusNode(); final FocusNode _timeFocusNode = FocusNode(); // Zustandsvariablen für die Validierung der Eingaben bool _isInitialCapitalEntered = false; bool _isMonthlySavingsRateEntered = false; bool _isInterestRateEntered = false; bool _isTimeEntered = false; @override void initState() { super.initState(); // Listener für die Eingabefelder, um die Validierung durchzuführen und Standardwerte wiederherzustellen _initialCapitalController.addListener(() { setState(() { _isInitialCapitalEntered = _initialCapitalController.text.isNotEmpty && isNumeric(_initialCapitalController.text); restoreDefaultValuesIfEmpty(_initialCapitalController); }); }); _monthlySavingsRateController.addListener(() { setState(() { _isMonthlySavingsRateEntered = _monthlySavingsRateController.text.isNotEmpty && isNumeric(_monthlySavingsRateController.text); restoreDefaultValuesIfEmpty(_monthlySavingsRateController); }); }); _interestRateController.addListener(() { setState(() { _isInterestRateEntered = _interestRateController.text.isNotEmpty && isNumeric(_interestRateController.text); restoreDefaultValuesIfEmpty(_interestRateController); }); }); _timeController.addListener(() { setState(() { _isTimeEntered = _timeController.text.isNotEmpty && isNumeric(_timeController.text); restoreDefaultValuesIfEmpty(_timeController); }); }); // Listener für die Fokus-Knoten, um die Eingabe zu runden, wenn der Fokus verloren geht _initialCapitalFocusNode.addListener(() { if (!_initialCapitalFocusNode.hasFocus) { roundToInteger(_initialCapitalController); } }); _monthlySavingsRateFocusNode.addListener(() { if (!_monthlySavingsRateFocusNode.hasFocus) { roundToInteger(_monthlySavingsRateController); } }); _interestRateFocusNode.addListener(() { if (!_interestRateFocusNode.hasFocus) { roundToInteger(_interestRateController); } }); _timeFocusNode.addListener(() { if (!_timeFocusNode.hasFocus) { roundToInteger(_timeController); } }); // Setzen von Beispielwerten für die Eingabefelder _initialCapitalController.text = '1000'; _monthlySavingsRateController.text = '50'; _interestRateController.text = '5'; _timeController.text = '10'; } double _initialCapital = 0.0; // Das anfängliche Kapital double _monthlySavingsRate = 0.0; // Der monatliche Sparbetrag double _interestRate = 0.0; // Der jährliche Zinssatz double _time = 0.0; // Der Anlagezeitraum in Jahren double _investedMoney = 0.0; // Das investierte Geld final List _investedMoneyList = []; // Liste, die das investierte Geld pro Jahr speichert PayoutInterval _payoutInterval = PayoutInterval.yearly; // Das Auszahlungsintervall (jährlich oder monatlich) double _compoundInterest = 0.0; // Der Zinseszins final List _compoundInterestList = []; // Liste, die den Zinseszins pro Jahr speichert // Methoden zum Festlegen der Werte aus den Eingabefeldern void setInitialCapital() { setState(() { _initialCapital = double.parse(_initialCapitalController.text); }); } void setMonthlySavingsRate() { setState(() { _monthlySavingsRate = double.parse(_monthlySavingsRateController.text); }); } void setInterestRate() { setState(() { _interestRate = double.parse(_interestRateController.text); }); } void setTime() { setState(() { _time = double.parse(_timeController.text); }); } CalculationPerformed _isCalculated = CalculationPerformed.noFirstTimeItLoaded; @override Widget build(BuildContext context) { final localizations = AppLocalizations.of(context)!; return Scaffold( body: SafeArea( child: Stack( children: [ SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Padding( padding: const EdgeInsets.all(20.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ InputWidget( label: localizations.initial_capital, controller: _initialCapitalController, focusNode: _initialCapitalFocusNode, isValid: _isInitialCapitalEntered, suffixText: localizations.currency, tooltipText: localizations.initial_capital_tooltiptext ), InputWidget( label: localizations.monthly_savings_rate, controller: _monthlySavingsRateController, focusNode: _monthlySavingsRateFocusNode, isValid: _isMonthlySavingsRateEntered, suffixText: localizations.currency, tooltipText: localizations.monthly_savings_rate_tooltiptext ), InputWidget( label: localizations.interest_rate, controller: _interestRateController, focusNode: _interestRateFocusNode, isValid: _isInterestRateEntered, suffixText: '%', tooltipText: localizations.interest_rate_tooltiptext ), InputWidget( label: localizations.investment_period, controller: _timeController, focusNode: _timeFocusNode, isValid: _isTimeEntered, suffixText: localizations.years, tooltipText: localizations.investment_period_tooltiptext ), IntervalWidget( selectedInterval: _payoutInterval == PayoutInterval.yearly ? localizations.yearly : localizations.monthly, onChanged: (newInterval) { setState(() { _payoutInterval = newInterval == localizations.yearly ? PayoutInterval.yearly : PayoutInterval.monthly; }); }, ), ElevatedButton( onPressed: () { if (_isInitialCapitalEntered && _isMonthlySavingsRateEntered && _isInterestRateEntered && _isTimeEntered) { setInitialCapital(); setMonthlySavingsRate(); setInterestRate(); setTime(); _investedMoney = calculateInvestedMoney(_initialCapital, _monthlySavingsRate, _time, _investedMoneyList); _compoundInterest = calculateCompoundInterest( _initialCapital, _monthlySavingsRate, _interestRate, _time, _payoutInterval, _investedMoneyList, _compoundInterestList ); _isCalculated = CalculationPerformed.yes; } else { _isCalculated = CalculationPerformed.no; } setState(() {}); }, style: ButtonStyle( backgroundColor: MaterialStateProperty.all(CupertinoColors.black), foregroundColor: MaterialStateProperty.all(CupertinoColors.white), shape: MaterialStateProperty.all( RoundedRectangleBorder( borderRadius: BorderRadius.circular(5), ), ), ), child: Text( localizations.calculate, style: const TextStyle( fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 20), if(_isCalculated == CalculationPerformed.yes) ResultWidget( compoundInterest: _compoundInterest.toStringAsFixed(0), investedMoney: _investedMoney.toStringAsFixed(0), time: _time.toStringAsFixed(0), monthlySavingsRate: _monthlySavingsRate.toStringAsFixed(0), interestRate: _interestRate.toStringAsFixed(0), payoutInterval: _payoutInterval, investedMoneyList: _investedMoneyList, compoundInterestList: _compoundInterestList, ), if(_isCalculated == CalculationPerformed.no) ErrWidget( errorMessage: localizations.invalid_input, ), ], ), ), ), Positioned( top: MediaQuery.of(context).size.height / 2 - 20, right: 10, child: LanguageSwitcher( currentLocale: Localizations.localeOf(context), onLocaleChanged: widget.onLocaleChanged, ), ), ], ), ), ); } }