diff --git a/lib/main.dart b/lib/main.dart index 7a78834..0017d3e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -37,23 +37,27 @@ class MyHomePage extends StatefulWidget { } 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(); - bool _isInitialCapitalEntered = false; - bool _isMonthlySavingsRateEntered = false; - bool _isInterestRateEntered = false; - bool _isTimeEntered = false; 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 && @@ -86,6 +90,7 @@ class _MyHomePageState extends State { }); }); + // Listener für die Fokus-Knoten, um die Eingabe zu runden, wenn der Fokus verloren geht _initialCapitalFocusNode.addListener(() { if (!_initialCapitalFocusNode.hasFocus) { roundToInteger(_initialCapitalController); @@ -110,10 +115,11 @@ class _MyHomePageState extends State { } }); - _initialCapitalController.text = '1000'; // Beispielwert für Anfangskapital - _monthlySavingsRateController.text = '50'; // Beispielwert für monatliche Sparrate - _interestRateController.text = '5'; // Beispielwert für jährlichen Zinssatz - _timeController.text = '10'; // Beispielwert für Anlagezeitraum + // Setzen von Beispielwerten für die Eingabefelder + _initialCapitalController.text = '1000'; + _monthlySavingsRateController.text = '50'; + _interestRateController.text = '5'; + _timeController.text = '10'; } @@ -122,12 +128,13 @@ class _MyHomePageState extends State { double _interestRate = 0.0; // Jährlicher Zinssatz double _time = 0.0; // Anlagezeitraum in Jahren double _investedMoney = 0.0; // Investiertes Geld ohne Zinsen - List _investedMoneyList = []; // Investiertes Geld ohne Zinsen (pro Jahr) + final List _investedMoneyList = []; // Investiertes Geld ohne Zinsen (pro Jahr) PayoutInterval _payoutInterval = PayoutInterval.yearly; // Standardwert für das Ausschüttungsintervall double _compoundInterest = 0.0; // Investiertes Geld mit Zinsen - List _compoundInterestList = []; // Investiertes Geld mit Zinsen (pro Jahr) + final List _compoundInterestList = []; // Investiertes Geld mit Zinsen (pro Jahr) bool _calculationPerformed = false; + // Methoden zum Festlegen der Werte aus den Eingabefeldern void setInitialCapital() { setState(() { _initialCapital = double.parse(_initialCapitalController.text); @@ -152,6 +159,7 @@ class _MyHomePageState extends State { }); } + // Methode zum Berechnen des investierten Geldes void _calculateInvestedMoney() { setState(() { _investedMoneyList.clear(); @@ -165,6 +173,7 @@ class _MyHomePageState extends State { }); } + // Methode zum Berechnen der Zinsen void _calculateCompoundInterest() { setState(() { _compoundInterestList.clear(); diff --git a/lib/utils.dart b/lib/utils.dart index 55ee7ad..9828862 100644 --- a/lib/utils.dart +++ b/lib/utils.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +// Rundet den Wert im Textfeld-Controller auf die nächste ganze Zahl void roundToInteger(TextEditingController controller) { double? parsedValue = double.tryParse(controller.text.replaceAll(',', '.')); if (parsedValue != null) { @@ -8,10 +9,12 @@ void roundToInteger(TextEditingController controller) { } } +// Überprüft, ob der gegebene Wert eine numerische Darstellung ist bool isNumeric(String value) { - return double.tryParse(value.replaceAll(',', '.')) != null; + return double.tryParse(value.replaceAll(',', '.')) != null; // Wert in einen double umwandeln } +// Setzt den Standardwert 0 für den Controller, wenn das Feld leer ist void restoreDefaultValuesIfEmpty(TextEditingController controller) { if (controller.text.isEmpty) { controller.text = '0'; diff --git a/lib/widgets/chart_widget.dart b/lib/widgets/chart_widget.dart index bc47f5b..02b0ee1 100644 --- a/lib/widgets/chart_widget.dart +++ b/lib/widgets/chart_widget.dart @@ -1,6 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:syncfusion_flutter_charts/charts.dart'; +// Widget für ein gestapeltes Säulendiagramm class StackedColumnChart extends StatelessWidget { final List lowerValues; final List upperValues; @@ -21,12 +22,14 @@ class StackedColumnChart extends StatelessWidget { title: AxisTitle(text: 'Euro'), ), series: [ + // Untere Teil der Säule StackedColumnSeries( dataSource: _getLowerChartData(), xValueMapper: (SalesData sales, _) => sales.year, yValueMapper: (SalesData sales, _) => sales.value, color: CupertinoColors.systemRed.highContrastColor, ), + // Obere Teil der Säule StackedColumnSeries( dataSource: _getUpperChartData(), xValueMapper: (SalesData sales, _) => sales.year, @@ -37,6 +40,7 @@ class StackedColumnChart extends StatelessWidget { ); } + // Methode zum Erstellen der Daten für den unteren Teil der Säule (Investiertes Geld) List _getLowerChartData() { List chartData = []; for (int i = 0; i < lowerValues.length; i++) { @@ -44,7 +48,7 @@ class StackedColumnChart extends StatelessWidget { } return chartData; } - + // Methode zum Erstellen der Daten für den oberen Teil der Säule (Investiertes Geld mit Zinsen) List _getUpperChartData() { List chartData = []; for (int i = 0; i < upperValues.length; i++) { diff --git a/lib/widgets/expandable_widget.dart b/lib/widgets/expandable_widget.dart index 75dda98..7051028 100644 --- a/lib/widgets/expandable_widget.dart +++ b/lib/widgets/expandable_widget.dart @@ -1,6 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +// Widget für eine erweiterbare Box class ExpandableBox extends StatefulWidget { final String headerText; final Widget expandedContent; @@ -19,6 +20,7 @@ class _ExpandableBoxState extends State { Widget build(BuildContext context) { return Column( children: [ + // GestureDetector zum Erfassen von Klicks zum Erweitern oder Verkleinern der Box GestureDetector( onTap: () { setState(() { diff --git a/lib/widgets/input_widget.dart b/lib/widgets/input_widget.dart index 787df86..16ece1a 100644 --- a/lib/widgets/input_widget.dart +++ b/lib/widgets/input_widget.dart @@ -1,6 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +// Funktion zum Erstellen eines Eingabe-Widgets Widget buildInputWidget(String label, TextEditingController controller, FocusNode focusNode, bool isValid, String suffixText, String tooltipText) { return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -8,6 +9,7 @@ Widget buildInputWidget(String label, TextEditingController controller, FocusNod Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + // Zeile für das Label und den Tooltip Row( children: [ Row( @@ -42,6 +44,7 @@ Widget buildInputWidget(String label, TextEditingController controller, FocusNod ], ), const SizedBox(height: 5), + // Textfeld für die Eingabe CupertinoTextField( controller: controller, focusNode: focusNode, diff --git a/lib/widgets/interval_widget.dart b/lib/widgets/interval_widget.dart index 9c3c947..18f2b53 100644 --- a/lib/widgets/interval_widget.dart +++ b/lib/widgets/interval_widget.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_application_1/enums.dart'; import 'package:flutter_application_1/translations.dart'; +// Widget zur Auswahl des Ausschüttungsintervalls class IntervalWidget extends StatefulWidget { final String selectedInterval; final Function(String) onChanged; @@ -22,6 +23,7 @@ class _IntervalWidgetState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + // Überschrift für das Dropdown-Menü const Row( children: [ Text( @@ -38,6 +40,7 @@ class _IntervalWidgetState extends State { ), ] ), + // Dropdown-Menü CupertinoTextField( placeholder: 'Ausschüttungsintervall auswählen', readOnly: true, @@ -49,6 +52,7 @@ class _IntervalWidgetState extends State { return Column( mainAxisSize: MainAxisSize.min, children: [ + // Liste von Auswahlmöglichkeiten Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: ListTile( @@ -61,6 +65,7 @@ class _IntervalWidgetState extends State { hoverColor: Colors.transparent, trailing: widget.selectedInterval == translateInterval(PayoutInterval.yearly) ? const Icon(CupertinoIcons.checkmark_alt) : null, onTap: () { + // Auswahl des jährlichen Intervalls und Schließen des Bottom Sheets widget.onChanged(translateInterval(PayoutInterval.yearly)); Navigator.pop(context); }, @@ -78,6 +83,7 @@ class _IntervalWidgetState extends State { hoverColor: Colors.transparent, trailing: widget.selectedInterval == translateInterval(PayoutInterval.monthly) ? const Icon(CupertinoIcons.checkmark_alt) : null, onTap: () { + // Auswahl des monatlichen Intervalls und Schließen des Bottom Sheets widget.onChanged(translateInterval(PayoutInterval.monthly)); Navigator.pop(context); }, diff --git a/lib/widgets/result_widget.dart b/lib/widgets/result_widget.dart index 12dd819..9d15bfd 100644 --- a/lib/widgets/result_widget.dart +++ b/lib/widgets/result_widget.dart @@ -4,7 +4,9 @@ import 'package:flutter_application_1/translations.dart'; import 'package:flutter_application_1/widgets/expandable_widget.dart'; import 'package:flutter_application_1/widgets/chart_widget.dart'; +// Erstellt das Widget für das Ergebnis der Berechnungen Widget buildResultWidget(String compoundInterest, String investedMoney, String time, String monthlySavingsRate, String interestRate, PayoutInterval payoutInterval, List investedMoneyList, List compoundInterestList) { + // Liste von Meilensteinen mit Werten, Bildern und Texten. List> milestoneList = [ {'value': 1329, 'image': 'iphone-15-pro-model.png', 'text': 'iPhone 15 Pro Max\nPreis: 1329€', 'size': 20}, {'value': 3071, 'image': 'flyer-gotour6-model.png', 'text': 'Flyer Gotour6 3.40\nPreis: 3071€', 'size': 70}, @@ -60,12 +62,14 @@ Widget _buildResultRow(String label, String value) { ); } +// Erstellt die Meilenstein-Timeline. Widget buildMilestoneTimeline(List> milestones, double totalInterest) { return SizedBox( child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: List.generate(milestones.length, (index) { + // Werte aus dem Meilenstein-Objekt extrahieren double milestoneValue = milestones[index]['value']; String milestoneImage = milestones[index]['image']; String milestoneText = milestones[index]['text']; @@ -73,7 +77,7 @@ Widget buildMilestoneTimeline(List> milestones, double tota bool milestoneReached = totalInterest >= milestoneValue; return Column( children: [ - if (index < milestones.length && index > 0) + if (index < milestones.length && index > 0) // Zeigt eine vertikale Linie an zwischen den Meilensteinen Container( height: 50, width: 2, @@ -88,7 +92,7 @@ Widget buildMilestoneTimeline(List> milestones, double tota width: milestoneSize, fit: BoxFit.cover, ), - const SizedBox(height: 5), // Abstand zwischen Bild und Text + const SizedBox(height: 5), Text( milestoneText, textAlign: TextAlign.center, @@ -99,6 +103,7 @@ Widget buildMilestoneTimeline(List> milestones, double tota ], ), ), + // Zeigt ein Häkchen oder einen Kreis je nach Erreichen des Meilensteins an Padding( padding: const EdgeInsets.symmetric(vertical: 4.0), child: Icon(