replaced milestone images with emojis and added some details
parent
7f05993257
commit
b791a4b69f
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 |
|
|
@ -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),
|
||||
],
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue