replaced milestone images with emojis and added some details

main
henryhdr 2024-05-20 16:34:31 +02:00
parent 7f05993257
commit b791a4b69f
11 changed files with 110 additions and 73 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 927 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 KiB

View File

@ -201,50 +201,52 @@ class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
buildInputWidget('Anfangskapital', _initialCapitalController, _initialCapitalFocusNode, _isInitialCapitalEntered, '', 'Das Anfangskapital ist der Betrag, den Sie zu Beginn Ihrer Anlage haben.'),
buildInputWidget('Monatliche Sparrate', _monthlySavingsRateController, _monthlySavingsRateFocusNode, _isMonthlySavingsRateEntered, '', 'Die monatliche Sparrate ist der Betrag, den Sie jeden Monat zu Ihrer Investition hinzufügen.'),
buildInputWidget('Jährlicher Zinssatz', _interestRateController, _interestRateFocusNode, _isInterestRateEntered, '%', 'Der jährliche Zinssatz ist der Prozentsatz, zu dem Ihr investiertes Kapital jedes Jahr wächst.'),
buildInputWidget('Anlagezeitraum', _timeController, _timeFocusNode, _isTimeEntered, 'Jahre', 'Der Anlagezeitraum ist die Zeitspanne, für die Sie planen, Ihr Geld anzulegen.'),
IntervalWidget(
selectedInterval: translateInterval(_payoutInterval),
onChanged: (newInterval) {
setState(() {
_payoutInterval = newInterval == 'jährlich' ? PayoutInterval.yearly : PayoutInterval.monthly;
});
},
),
ElevatedButton(
onPressed: () {
setInitialCapital();
setMonthlySavingsRate();
setInterestRate();
setTime();
_calculateInvestedMoney();
_calculateCompoundInterest();
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(CupertinoColors.black),
foregroundColor: MaterialStateProperty.all<Color>(CupertinoColors.white),
body: SafeArea(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
buildInputWidget('Anfangskapital', _initialCapitalController, _initialCapitalFocusNode, _isInitialCapitalEntered, '', 'Das Anfangskapital ist der Betrag, den Sie zu Beginn Ihrer Anlage haben.'),
buildInputWidget('Monatliche Sparrate', _monthlySavingsRateController, _monthlySavingsRateFocusNode, _isMonthlySavingsRateEntered, '', 'Die monatliche Sparrate ist der Betrag, den Sie jeden Monat zu Ihrer Investition hinzufügen.'),
buildInputWidget('Jährlicher Zinssatz', _interestRateController, _interestRateFocusNode, _isInterestRateEntered, '%', 'Der jährliche Zinssatz ist der Prozentsatz, zu dem Ihr investiertes Kapital jedes Jahr wächst.'),
buildInputWidget('Anlagezeitraum', _timeController, _timeFocusNode, _isTimeEntered, 'Jahre', 'Der Anlagezeitraum ist die Zeitspanne, für die Sie planen, Ihr Geld anzulegen.'),
IntervalWidget(
selectedInterval: translateInterval(_payoutInterval),
onChanged: (newInterval) {
setState(() {
_payoutInterval = newInterval == 'jährlich' ? PayoutInterval.yearly : PayoutInterval.monthly;
});
},
),
child: const Text(
'Berechnen',
style: TextStyle(
fontWeight: FontWeight.bold,
ElevatedButton(
onPressed: () {
setInitialCapital();
setMonthlySavingsRate();
setInterestRate();
setTime();
_calculateInvestedMoney();
_calculateCompoundInterest();
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(CupertinoColors.black),
foregroundColor: MaterialStateProperty.all<Color>(CupertinoColors.white),
),
child: const Text(
'Berechnen',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(height: 20),
if(_calculationPerformed)
buildResultWidget('$_compoundInterest', '$_investedMoney', '$_time', '$_monthlySavingsRate', '$_interestRate', _payoutInterval, _investedMoneyList, _compoundInterestList),
],
),
const SizedBox(height: 20),
if(_calculationPerformed)
buildResultWidget('$_compoundInterest', '$_investedMoney', '$_time', '$_monthlySavingsRate', '$_interestRate', _payoutInterval, _investedMoneyList, _compoundInterestList),
],
),
)
)
)
);

View File

@ -15,6 +15,10 @@ class StackedColumnChart extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SfCartesianChart(
legend: const Legend(
isVisible: true, // Legende anzeigen
position: LegendPosition.top, // Legende unterhalb des Diagramms platzieren
),
primaryXAxis: const CategoryAxis(
title: AxisTitle(text: 'Jahr'),
),
@ -27,6 +31,7 @@ class StackedColumnChart extends StatelessWidget {
dataSource: _getLowerChartData(),
xValueMapper: (SalesData sales, _) => sales.year,
yValueMapper: (SalesData sales, _) => sales.value,
name: 'Einzahlungen',
color: CupertinoColors.systemRed.highContrastColor,
),
// Obere Teil der Säule
@ -34,9 +39,17 @@ class StackedColumnChart extends StatelessWidget {
dataSource: _getUpperChartData(),
xValueMapper: (SalesData sales, _) => sales.year,
yValueMapper: (SalesData sales, _) => sales.value,
name: 'Zinsen',
color: CupertinoColors.systemBlue.highContrastColor,
),
],
// Trackball für Hover-Interaktion
trackballBehavior: TrackballBehavior(
enable: true,
tooltipSettings: const InteractiveTooltip(enable: true),
activationMode: ActivationMode.singleTap,
hideDelay: 2000,
),
);
}

View File

@ -24,6 +24,15 @@ Widget buildInputWidget(String label, TextEditingController controller, FocusNod
const SizedBox(width: 5),
Tooltip(
message: tooltipText,
triggerMode: TooltipTriggerMode.tap,
decoration: const BoxDecoration(
color: CupertinoColors.black,
borderRadius: BorderRadius.all(Radius.circular(5))
),
textStyle: const TextStyle(
color: CupertinoColors.white,
),
margin: const EdgeInsets.all(20),
child: const Icon(CupertinoIcons.question_circle_fill, size: 15),
),
],

View File

@ -36,6 +36,15 @@ class _IntervalWidgetState extends State<IntervalWidget> {
SizedBox(width: 5),
Tooltip(
message: 'Das Ausschüttungsintervall bezieht sich darauf, wie oft die Erträge aus Ihrer Investition ausgeschüttet werden.',
triggerMode: TooltipTriggerMode.tap,
decoration: BoxDecoration(
color: CupertinoColors.black,
borderRadius: BorderRadius.all(Radius.circular(5))
),
textStyle: TextStyle(
color: CupertinoColors.white,
),
margin: EdgeInsets.all(20),
child: Icon(CupertinoIcons.question_circle_fill, size: 15),
),
]

View File

@ -8,16 +8,16 @@ import 'package:flutter_application_1/widgets/chart_widget.dart';
Widget buildResultWidget(String compoundInterest, String investedMoney, String time, String monthlySavingsRate, String interestRate, PayoutInterval payoutInterval, List<double> investedMoneyList, List<double> compoundInterestList) {
// Liste von Meilensteinen mit Werten, Bildern und Texten.
List<Map<String, dynamic>> 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},
{'value': 248157, 'image': 'porsche-model.png', 'text': 'Porsche 992 GT3 RS\nPreis: 248157€', 'size': 100},
{'value': 450000, 'image': 'real-estate-model.png', 'text': '150qm Einfamilienhaus\nPreis: ca. 450000€', 'size': 100},
{'value': 1329.0, 'emoji': '📱', 'text': 'iPhone 15 Pro Max\nPreis: 1329€'},
{'value': 3071.0, 'emoji': '🚲', 'text': 'Flyer Gotour6 3.40\nPreis: 3071€'},
{'value': 248157.0, 'emoji': '🏎️', 'text': 'Porsche 992 GT3 RS\nPreis: 248157€'},
{'value': 450000.0, 'emoji': '🏡', 'text': '150qm Einfamilienhaus\nPreis: ca. 450000€'},
];
return Column(
children: <Widget>[
_buildResultRow('Endkapital:', '$compoundInterest'),
_buildResultRow('Gesamte Einzahlungen:', '$investedMoney'),
_buildResultRow('Erhaltene Zinszahlungen:', '${double.parse(compoundInterest) - double.parse(investedMoney)}'),
_buildResultRow('Endkapital:', '$compoundInterest'),
_buildResultRow('Einzahlungen:', '$investedMoney'),
_buildResultRow('Erhaltene Zinsen:', '${double.parse(compoundInterest) - double.parse(investedMoney)}'),
const SizedBox(height: 20),
Text(
'Wenn du über einen Zeitraum von $time Jahren ${translateInterval(payoutInterval)} $monthlySavingsRate€ mit einem Zinssatz von $interestRate% investierst, erreichst du am Ende ein Endkapital von $compoundInterest€. Dieses setzt sich aus Einzahlungen von $investedMoney€ und Zinsen bzw. Kapitalerträgen in Höhe von ${double.parse(compoundInterest) - double.parse(investedMoney)}€ zusammen.'
@ -41,20 +41,27 @@ Widget buildResultWidget(String compoundInterest, String investedMoney, String t
Widget _buildResultRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 100),
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
label,
style: const TextStyle(
fontWeight: FontWeight.bold,
Flexible(
child: Text(
label,
textAlign: TextAlign.start,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
),
Text(
value,
style: const TextStyle(
fontWeight: FontWeight.bold,
const SizedBox(width: 20),
Flexible(
child: Text(
value,
textAlign: TextAlign.end,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
),
],
@ -62,6 +69,8 @@ Widget _buildResultRow(String label, String value) {
);
}
// Erstellt die Meilenstein-Timeline.
Widget buildMilestoneTimeline(List<Map<String, dynamic>> milestones, double totalInterest) {
return SizedBox(
@ -71,13 +80,12 @@ Widget buildMilestoneTimeline(List<Map<String, dynamic>> milestones, double tota
children: List.generate(milestones.length, (index) {
// Werte aus dem Meilenstein-Objekt extrahieren
double milestoneValue = milestones[index]['value'];
String milestoneImage = milestones[index]['image'];
String milestoneEmoji = milestones[index]['emoji'];
String milestoneText = milestones[index]['text'];
double milestoneSize = milestones[index]['size'];
bool milestoneReached = totalInterest >= milestoneValue;
return Column(
children: [
if (index < milestones.length && index > 0) // Zeigt eine vertikale Linie an zwischen den Meilensteinen
if (index > 0) // Zeigt eine vertikale Linie an zwischen den Meilensteinen
Container(
height: 50,
width: 2,
@ -87,10 +95,9 @@ Widget buildMilestoneTimeline(List<Map<String, dynamic>> milestones, double tota
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Column(
children: [
Image.asset(
'assets/images/$milestoneImage',
width: milestoneSize,
fit: BoxFit.cover,
Text(
milestoneEmoji,
style: const TextStyle(fontSize: 25),
),
const SizedBox(height: 5),
Text(

View File

@ -188,18 +188,18 @@ packages:
dependency: "direct main"
description:
name: syncfusion_flutter_charts
sha256: "75253e2d32ce2e739c8efe0aec52668334d880e2a96f6d0d2b4422f49af7c608"
sha256: "01ff26c73725cb4f9d04492daae4d0365c2ed2cbf43cd83132a24f47d4d4931c"
url: "https://pub.dev"
source: hosted
version: "25.1.42+1"
version: "25.2.4"
syncfusion_flutter_core:
dependency: transitive
description:
name: syncfusion_flutter_core
sha256: fc61878342caee6da7979ca0ca9bb178f1eb5ca9b836dada34b83caa39e4bfed
sha256: "9e8bac2367d03bd902844f59e866c0e7b1e10b0b8fa5a6a926c0d8ae8c344533"
url: "https://pub.dev"
source: hosted
version: "25.1.42"
version: "25.2.4"
term_glyph:
dependency: transitive
description:

View File

@ -60,11 +60,8 @@ flutter:
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- assets/images/iphone-15-pro-model.png
- assets/images/flyer-gotour6-model.png
- assets/images/porsche-model.png
- assets/images/real-estate-model.png
# assets:
# - assets/images/
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware