Darkmode+ budgetchecker finished

main
Arlind 2023-06-17 03:09:31 +02:00
parent 5582e7b4fa
commit db9abf9866
13 changed files with 727 additions and 283 deletions

View File

@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_neumorphic/flutter_neumorphic.dart'; import 'package:flutter_neumorphic/flutter_neumorphic.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:tests/saving_tips.dart'; import 'package:tests/saving_tips.dart';
import 'package:tests/theme/theme_constants.dart';
import 'package:tests/transaction/transaction_dialog.dart'; import 'package:tests/transaction/transaction_dialog.dart';
import 'package:tests/transaction/transaction.dart'; import 'package:tests/transaction/transaction.dart';
import '../main.dart'; import '../main.dart';
@ -30,35 +31,41 @@ class AccountDetailPageState extends State<AccountDetailPage>
List<Transaction> incomeTransactions = []; List<Transaction> incomeTransactions = [];
List<Transaction> expenseTransactions = []; List<Transaction> expenseTransactions = [];
List<ExpenseData> expenseData = []; List<ExpenseData> expenseData = [];
String _selectedCurrency=""; String _selectedCurrency = "";
Future<String> getCurrencyFromSharedPreferences(String key) async { Future<String> getCurrencyFromSharedPreferences(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
if (prefs.getString(key)=="Euro"){ if (prefs.getString(key) == "Euro") {
_selectedCurrency=""; _selectedCurrency = "";
} }
if (prefs.getString(key)=="Dollar"){ if (prefs.getString(key) == "Dollar") {
_selectedCurrency=r"$"; _selectedCurrency = r"$";
} }
if (prefs.getString(key)=="CHF"){ if (prefs.getString(key) == "CHF") {
_selectedCurrency="CHF"; _selectedCurrency = "CHF";
} }
return prefs.getString(key) ?? 'Euro'; return prefs.getString(key) ?? 'Euro';
} }
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_tabController = TabController(length: 3, vsync: this); _tabController = TabController(length: 3, vsync: this);
getCurrencyFromSharedPreferences("currency").then((value) { getCurrencyFromSharedPreferences("currency").then((value) {
setState(() { setState(() {});
});
}); });
loadMaxProgress();
loadTransactions(); loadTransactions();
} }
void loadMaxProgress() async {
double storedMaxProgress = await getMaxProgress();
setState(() {
maxProgress = storedMaxProgress;
});
}
@override @override
void dispose() { void dispose() {
_tabController.dispose(); _tabController.dispose();
@ -141,8 +148,24 @@ class AccountDetailPageState extends State<AccountDetailPage>
final _budgetController = TextEditingController(); final _budgetController = TextEditingController();
double progress = 0; double progress = 0;
double submitbudget() { double submitBudget() {
return progress = double.parse(_budgetController.text.trim()); if (_budgetController.text.isNotEmpty) {
double budgetValue = double.parse(_budgetController.text);
SharedPreferences.getInstance().then((prefs) {
prefs.setDouble("maxProgress", budgetValue);
});
setState(() {
maxProgress = budgetValue;
});
return budgetValue;
}
return 0;
}
Future<double> getMaxProgress() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
double maxProgress = prefs.getDouble('maxProgress') ?? 1000;
return maxProgress;
} }
@override @override
@ -155,9 +178,9 @@ class AccountDetailPageState extends State<AccountDetailPage>
Padding( Padding(
padding: const EdgeInsets.only(right: 10.0), padding: const EdgeInsets.only(right: 10.0),
child: IconButton( child: IconButton(
icon: const Icon( icon: Icon(
Icons.info, Icons.info,
color: Colors.grey, color: Theme.of(context).unselectedWidgetColor,
), ),
onPressed: () { onPressed: () {
showDialog( showDialog(
@ -171,11 +194,12 @@ class AccountDetailPageState extends State<AccountDetailPage>
toolbarHeight: 80, toolbarHeight: 80,
title: Text( title: Text(
widget.account.name, widget.account.name,
style: const TextStyle( style: TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.black54, color: Theme.of(context).brightness == Brightness.dark
), ? Colors.white70
: Colors.black87),
), ),
centerTitle: true, centerTitle: true,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
@ -184,13 +208,12 @@ class AccountDetailPageState extends State<AccountDetailPage>
bottomRight: Radius.circular(15), bottomRight: Radius.circular(15),
), ),
), ),
shadowColor: Colors.grey.shade300,
leading: Padding( leading: Padding(
padding: const EdgeInsets.only(left: 16.0), padding: const EdgeInsets.only(left: 16.0),
child: NeumorphicButton( child: NeumorphicButton(
onPressed: () { onPressed: () {
Navigator.pop(context); // Zurück zur vorherigen Seite Navigator.pop(context);
Navigator.pushReplacement( // Neue Seite öffnen und vorherige Seite ersetzen Navigator.pushReplacement(
context, context,
MaterialPageRoute(builder: (context) => const HomePage()), MaterialPageRoute(builder: (context) => const HomePage()),
); );
@ -199,11 +222,20 @@ class AccountDetailPageState extends State<AccountDetailPage>
shape: NeumorphicShape.flat, shape: NeumorphicShape.flat,
boxShape: const NeumorphicBoxShape.circle(), boxShape: const NeumorphicBoxShape.circle(),
depth: 6, depth: 6,
shadowLightColor: Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
intensity: 0.9, intensity: 0.9,
color: Colors.grey.shade100,
), ),
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(8),
child: const Icon(Icons.arrow_back, color: Colors.black38), child: Icon(Icons.arrow_back,
color: Theme.of(context).unselectedWidgetColor),
), ),
), ),
), ),
@ -211,12 +243,12 @@ class AccountDetailPageState extends State<AccountDetailPage>
children: [ children: [
TabBar( TabBar(
controller: _tabController, controller: _tabController,
labelColor: Colors.black, labelColor: Theme.of(context).cardColor,
labelStyle: const TextStyle(fontSize: 14), labelStyle: const TextStyle(fontSize: 14),
unselectedLabelColor: Colors.black54, unselectedLabelColor: Theme.of(context).unselectedWidgetColor,
indicator: MaterialIndicator( indicator: MaterialIndicator(
height: 4, height: 4,
color: Colors.black54, color: Theme.of(context).unselectedWidgetColor,
topLeftRadius: 8, topLeftRadius: 8,
topRightRadius: 8, topRightRadius: 8,
horizontalPadding: 45, horizontalPadding: 45,
@ -249,16 +281,27 @@ class AccountDetailPageState extends State<AccountDetailPage>
Neumorphic( Neumorphic(
margin: const EdgeInsets.all(14), margin: const EdgeInsets.all(14),
style: NeumorphicStyle( style: NeumorphicStyle(
color: Colors.grey.shade100, shadowLightColor:
Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor:
Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
boxShape: NeumorphicBoxShape.roundRect( boxShape: NeumorphicBoxShape.roundRect(
BorderRadius.circular(15)), BorderRadius.circular(15)),
depth: -5, depth: -5,
intensity: 0.8, intensity: 0.8,
), ),
child: TextFormField( child: TextFormField(
controller: _budgetController,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'enteramount'.tr(), labelText: 'enterbudget'.tr(),
contentPadding: const EdgeInsets.only( contentPadding: const EdgeInsets.only(
left: 16, bottom: 8, top: 8), left: 16, bottom: 8, top: 8),
border: InputBorder.none, border: InputBorder.none,
@ -268,13 +311,25 @@ class AccountDetailPageState extends State<AccountDetailPage>
const SizedBox(height: 16), const SizedBox(height: 16),
NeumorphicButton( NeumorphicButton(
onPressed: () { onPressed: () {
progress = submitbudget(); setState(() {
submitBudget();
});
}, },
style: NeumorphicStyle( style: NeumorphicStyle(
boxShape: NeumorphicBoxShape.roundRect( boxShape: NeumorphicBoxShape.roundRect(
BorderRadius.circular(12), BorderRadius.circular(12),
), ),
color: Colors.grey.shade100, shadowLightColor:
Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor:
Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
depth: 8, depth: 8,
intensity: 0.9, intensity: 0.9,
), ),
@ -295,15 +350,23 @@ class AccountDetailPageState extends State<AccountDetailPage>
style: NeumorphicStyle( style: NeumorphicStyle(
depth: 8, depth: 8,
intensity: 1, intensity: 1,
shadowDarkColor: Colors.grey.shade400, shadowLightColor: Theme.of(context).brightness == Brightness.light
color: Colors.grey.shade100, ? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
boxShape: const NeumorphicBoxShape.circle(), boxShape: const NeumorphicBoxShape.circle(),
), ),
padding: const EdgeInsets.all(16), child: Icon(
child: const Icon(
Icons.add, Icons.add,
size: 40, size: 60,
color: Colors.black12, color: Theme.of(context).brightness == Brightness.light
? Colors.black12
: Colors.white12,
), ),
), ),
); );
@ -311,14 +374,20 @@ class AccountDetailPageState extends State<AccountDetailPage>
final ValueNotifier<double> _valueNotifier = ValueNotifier(0); final ValueNotifier<double> _valueNotifier = ValueNotifier(0);
double maxProgress = 500;
Widget monthlybudgetplanner() { Widget monthlybudgetplanner() {
return CircularSeekBar( return CircularSeekBar(
width: double.infinity, width: double.infinity,
height: 300, height: 300,
trackColor: Colors.black12, trackColor: Theme.of(context).brightness == Brightness.light
progress: 500, ? Colors.black12
: Colors.white12,
progress: calculateMonthlyExpensesTotal(),
minProgress: 0, minProgress: 0,
maxProgress: 800, maxProgress: calculateMonthlyExpensesTotal() > maxProgress
? calculateMonthlyExpensesTotal()
: maxProgress,
barWidth: 17, barWidth: 17,
startAngle: 45, startAngle: 45,
sweepAngle: 270, sweepAngle: 270,
@ -338,10 +407,9 @@ class AccountDetailPageState extends State<AccountDetailPage>
], ],
innerThumbRadius: 0, innerThumbRadius: 0,
innerThumbStrokeWidth: 12, innerThumbStrokeWidth: 12,
innerThumbColor: Colors.white, innerThumbColor: Theme.of(context).cardColor,
outerThumbRadius: 0, outerThumbRadius: 0,
outerThumbStrokeWidth: 15, outerThumbStrokeWidth: 15,
outerThumbColor: Colors.blueAccent,
dashWidth: 1.5, dashWidth: 1.5,
dashGap: 1.9, dashGap: 1.9,
animation: true, animation: true,
@ -350,24 +418,59 @@ class AccountDetailPageState extends State<AccountDetailPage>
valueNotifier: _valueNotifier, valueNotifier: _valueNotifier,
child: Center( child: Center(
child: ValueListenableBuilder( child: ValueListenableBuilder(
valueListenable: _valueNotifier, valueListenable: _valueNotifier,
builder: (_, double value, __) => Column( builder: (_, double value, __) {
mainAxisSize: MainAxisSize.min, final isMaxProgressReached = value >= maxProgress;
children: [ final textStyle = TextStyle(
Text( fontSize: 15,
'${value.round()}$_selectedCurrency', fontWeight:
), isMaxProgressReached ? FontWeight.w600 : FontWeight.w300,
Text( );
'progress'.tr(),
), return Column(
], mainAxisSize: MainAxisSize.min,
)), children: [
if (isMaxProgressReached)
Text(
"budgetmax".tr(),
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Theme.of(context).cardColor),
)
else
Text(
'${value.round()}$_selectedCurrency',
style: TextStyle(
fontSize: 24, color: Theme.of(context).cardColor),
),
const SizedBox(
height: 10,
),
isMaxProgressReached
? Text('hint'.tr(),
textAlign: TextAlign.center,
style: TextStyle(color: Theme.of(context).cardColor))
: Text('progress'.tr(),
style: TextStyle(color: Theme.of(context).cardColor)),
const SizedBox(height: 10),
isMaxProgressReached
? Container()
: Text(
'Budget: $maxProgress',
style: textStyle,
),
],
);
},
),
), ),
); );
} }
Widget _buildTransactionsList(List<Transaction> transactionsList) { Widget _buildTransactionsList(List<Transaction> transactionsList) {
return ListView.builder( return ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: transactionsList.length, itemCount: transactionsList.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return ListTile( return ListTile(
@ -389,11 +492,25 @@ class AccountDetailPageState extends State<AccountDetailPage>
); );
} }
double calculateMonthlyExpensesTotal() {
double total = 0;
for (var transaction in expenseTransactions) {
String month = DateFormat('yyyy-MM').format(transaction.date);
if (month == DateFormat('yyyy-MM').format(DateTime.now())) {
total += transaction.amount;
}
}
return total;
}
Widget _buildExpenseChart() { Widget _buildExpenseChart() {
return Padding( return Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Card( child: Card(
elevation: 4.0, color: Theme.of(context).brightness == Brightness.light
? grey400
: grey800,
elevation: 6.0,
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: MonthlyExpensesChart(data: expenseData), child: MonthlyExpensesChart(data: expenseData),

View File

@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_neumorphic/flutter_neumorphic.dart'; import 'package:flutter_neumorphic/flutter_neumorphic.dart';
import '../theme/theme_constants.dart';
import 'account.dart'; import 'account.dart';
class AddAccountDialog extends StatefulWidget { class AddAccountDialog extends StatefulWidget {
@ -33,7 +34,6 @@ class AddAccountDialogState extends State<AddAccountDialog> {
balance: balance, balance: balance,
); );
widget.addAccount(account); widget.addAccount(account);
Navigator.of(context).pop(); Navigator.of(context).pop();
} }
} }
@ -48,7 +48,6 @@ class AddAccountDialogState extends State<AddAccountDialog> {
'addaccount'.tr(), 'addaccount'.tr(),
), ),
titleTextStyle: const TextStyle( titleTextStyle: const TextStyle(
color: Colors.black54,
fontSize: 20, fontSize: 20,
), ),
content: Form( content: Form(
@ -60,7 +59,16 @@ class AddAccountDialogState extends State<AddAccountDialog> {
style: NeumorphicStyle( style: NeumorphicStyle(
depth: -5, depth: -5,
intensity: 0.8, intensity: 0.8,
color: Colors.grey.shade100, shadowLightColor:
Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
boxShape: NeumorphicBoxShape.roundRect( boxShape: NeumorphicBoxShape.roundRect(
BorderRadius.circular(12), BorderRadius.circular(12),
), ),
@ -85,7 +93,16 @@ class AddAccountDialogState extends State<AddAccountDialog> {
style: NeumorphicStyle( style: NeumorphicStyle(
depth: -5, depth: -5,
intensity: 0.8, intensity: 0.8,
color: Colors.grey.shade100, shadowLightColor:
Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
boxShape: NeumorphicBoxShape.roundRect( boxShape: NeumorphicBoxShape.roundRect(
BorderRadius.circular(12), BorderRadius.circular(12),
), ),
@ -114,6 +131,7 @@ class AddAccountDialogState extends State<AddAccountDialog> {
), ),
actions: [ actions: [
NeumorphicButton( NeumorphicButton(
margin: const EdgeInsets.fromLTRB(0, 0, 4, 4),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
@ -124,7 +142,15 @@ class AddAccountDialogState extends State<AddAccountDialog> {
boxShape: NeumorphicBoxShape.roundRect( boxShape: NeumorphicBoxShape.roundRect(
BorderRadius.circular(12), BorderRadius.circular(12),
), ),
color: Colors.grey.shade100, shadowLightColor: Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
), ),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
child: Text( child: Text(
@ -144,7 +170,15 @@ class AddAccountDialogState extends State<AddAccountDialog> {
boxShape: NeumorphicBoxShape.roundRect( boxShape: NeumorphicBoxShape.roundRect(
BorderRadius.circular(12), BorderRadius.circular(12),
), ),
color: Colors.grey.shade100, shadowLightColor: Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
), ),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
child: Text( child: Text(

View File

@ -1,15 +1,15 @@
{ {
"title" : "My Finance Planner", "title": "My Finance Planner",
"delete" : "Löschen", "delete": "Löschen",
"deleteaccount" : "Account löschen", "deleteaccount": "Account löschen",
"sure" : "Sind Sie sicher, dass Sie dieses Konto löschen möchten?", "sure": "Sind Sie sicher, dass Sie dieses Konto löschen möchten?",
"balance" : "Bilanz", "balance": "Bilanz",
"addaccount" : "Konto hinzufügen", "addaccount": "Konto hinzufügen",
"entername" : "Bitte geben Sie einen Namen ein", "entername": "Bitte geben Sie einen Namen ein",
"enterbalance" : "Bitte geben Sie einen Saldo ein", "enterbalance": "Bitte geben Sie einen Saldo ein",
"entervalidnumber" : "Bitte geben Sie eine gültige Nummer ein", "entervalidnumber": "Bitte geben Sie eine gültige Nummer ein",
"cancel" : "Abbrechen", "cancel": "Abbrechen",
"add" : "Hinzufügen", "add": "Hinzufügen",
"income": "Einnahmen", "income": "Einnahmen",
"expenditures": "Ausgaben", "expenditures": "Ausgaben",
"addtrans": "Transaktion hinzufügen", "addtrans": "Transaktion hinzufügen",
@ -24,5 +24,23 @@
"budget": "Budgetcheck", "budget": "Budgetcheck",
"progress": "von deinem Budget ausgegeben", "progress": "von deinem Budget ausgegeben",
"monthlyexpenses": "Monatliche Ausgaben", "monthlyexpenses": "Monatliche Ausgaben",
"close": "Schließen" "close": "Schließen",
"tip1": "Spare jeden Monat einen festen Betrag.",
"tip2": "Vergleiche Preise, bevor du etwas kaufst.",
"tip3": "Vermeide unnötige Ausgaben.",
"tip4": "Setze dir konkrete Sparziele.",
"tip5": "Überprüfe regelmäßig deine Ausgaben.",
"tip6": "Verkaufe Dinge, die du nicht mehr brauchst.",
"tip7": "Nutze Cashback-Programme beim Einkaufen.",
"tip8": "Koche selbst anstatt auswärts zu essen.",
"tip9": "Nutze kostenlose Angebote und Gutscheine.",
"tip10": "Vermeide Impulskäufe und schlafe vor größeren Ausgaben eine Nacht darüber.",
"tip11": "Fahre mit dem Fahrrad oder öffentlichen Verkehrsmitteln anstatt mit dem Auto.",
"tip12": "Plane deine Mahlzeiten im Voraus, um Lebensmittelverschwendung zu vermeiden.",
"tip13": "Vergleiche Versicherungen und Verträge, um Geld zu sparen.",
"tip14": "Mache deine eigenen Reinigungsmittel statt teure Produkte zu kaufen.",
"tip15": "Nutze kostenlose Online-Ressourcen für Weiterbildung und Hobbys.",
"hint": "Spartipps gefällig? \nDrücke auf den Info-Button",
"budgetmax": "Budget verbraucht!",
"enterbudget": "Budget eingeben"
} }

View File

@ -1,15 +1,15 @@
{ {
"title" : "My Finance Planner", "title": "My Finance Planner",
"delete" : "Delete", "delete": "Delete",
"deleteaccount" : "Delete account", "deleteaccount": "Delete account",
"sure" : "Are you sure you want to delete this account?", "sure": "Are you sure you want to delete this account?",
"balance" : "Balance", "balance": "Balance",
"addaccount" : "Add account", "addaccount": "Add account",
"entername" : "Please enter a name", "entername": "Please enter a name",
"enterbalance" : "Please enter a balance", "enterbalance": "Please enter a balance",
"entervalidnumber" : "Please enter a valid number", "entervalidnumber": "Please enter a valid number",
"cancel" : "Cancel", "cancel": "Cancel",
"add" : "Add", "add": "Add",
"income": "Income", "income": "Income",
"expenditures": "Expenses", "expenditures": "Expenses",
"addtrans": "Add transaction", "addtrans": "Add transaction",
@ -24,5 +24,23 @@
"budget": "Budget check", "budget": "Budget check",
"progress": "of your budget spent", "progress": "of your budget spent",
"monthlyexpenses": "Monthly Expenses", "monthlyexpenses": "Monthly Expenses",
"close": "Close" "close": "Close",
"tip1":"Save a fixed amount every month",
"tip2":"Compare prices before you buy anything",
"tip3":"Avoid unnecessary spending.",
"tip4":"Set specific savings goals.",
"tip5":"Review your spending regularly.",
"tip6":"Sell things you no longer need",
"tip7":"Take advantage of cash-back programs when shopping.",
"tip8":"Cook for yourself instead of eating out.",
"tip9":"Take advantage of free offers and coupons.",
"tip10":"Avoid impulse buys and sleep on it before spending big.",
"tip11":"Ride a bike or take public transportation instead of driving.",
"tip12":"Plan your meals ahead of time to avoid food waste.",
"tip13":"Compare insurance policies and contracts to save money.",
"tip14":"Make your own cleaning supplies instead of buying expensive products.",
"tip15":"Use free online resources for continuing education and hobbies.",
"hint": "Need saving tips? \nPress the info button",
"budgetmax": "Budget spent!",
"enterbudget": "Enter budget"
} }

View File

@ -1,5 +1,6 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:syncfusion_flutter_charts/charts.dart'; import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:tests/theme/theme_constants.dart';
import 'expense_data.dart'; import 'expense_data.dart';
import 'package:flutter_neumorphic/flutter_neumorphic.dart'; import 'package:flutter_neumorphic/flutter_neumorphic.dart';
@ -16,13 +17,22 @@ class MonthlyExpensesChart extends StatelessWidget {
style: NeumorphicStyle( style: NeumorphicStyle(
shape: NeumorphicShape.flat, shape: NeumorphicShape.flat,
depth: 8, depth: 8,
intensity: 0.6, intensity: 0.7,
surfaceIntensity: 0.25, surfaceIntensity: 0.25,
shadowLightColor: Colors.white, shadowLightColor: Theme.of(context).brightness == Brightness.light
shadowDarkColor: Colors.black87, ? const NeumorphicStyle().shadowLightColor
color: Colors.grey[100], : grey600,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
), ),
child: SfCartesianChart( child: SfCartesianChart(
backgroundColor: Theme.of(context).brightness == Brightness.light
? grey200
: grey700,
primaryXAxis: CategoryAxis(), primaryXAxis: CategoryAxis(),
series: _buildChartSeries(), series: _buildChartSeries(),
tooltipBehavior: TooltipBehavior(enable: true), tooltipBehavior: TooltipBehavior(enable: true),
@ -51,4 +61,4 @@ class MonthlyExpensesChart extends StatelessWidget {
), ),
]; ];
} }
} }

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:awesome_dialog/awesome_dialog.dart'; import 'package:awesome_dialog/awesome_dialog.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_neumorphic/flutter_neumorphic.dart'; import 'package:flutter_neumorphic/flutter_neumorphic.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:tests/preferences.dart'; import 'package:tests/preferences.dart';
import 'package:tests/theme/theme_constants.dart'; import 'package:tests/theme/theme_constants.dart';
@ -15,14 +16,16 @@ Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized(); await EasyLocalization.ensureInitialized();
runApp( runApp(
EasyLocalization( ChangeNotifierProvider(
supportedLocales: const [Locale('en', 'US'), Locale('de', 'DE')], create: (context) => ThemeManager(),
path: 'lib/assets/translations', child: EasyLocalization(
// <-- change the path of the translation files supportedLocales: const [Locale('en', 'US'), Locale('de', 'DE')],
fallbackLocale: const Locale('en', 'US'), path: 'lib/assets/translations',
child: const FinancialPlannerApp()), // <-- change the path of the translation files
); fallbackLocale: const Locale('en', 'US'),
} child: const FinancialPlannerApp()),
));
}
ThemeManager _themeManager = ThemeManager(); ThemeManager _themeManager = ThemeManager();
@ -31,7 +34,8 @@ class FinancialPlannerApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); SystemChrome.setEnabledSystemUIMode(
SystemUiMode.manual, overlays: [SystemUiOverlay.top]);
return MaterialApp( return MaterialApp(
localizationsDelegates: context.localizationDelegates, localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales, supportedLocales: context.supportedLocales,
@ -40,7 +44,7 @@ class FinancialPlannerApp extends StatelessWidget {
title: 'title'.tr(), title: 'title'.tr(),
theme: lightTheme, theme: lightTheme,
darkTheme: darkTheme, darkTheme: darkTheme,
themeMode: _themeManager.themeMode, themeMode: Provider.of<ThemeManager>(context).themeMode,
home: const HomePage(), home: const HomePage(),
); );
} }
@ -55,18 +59,18 @@ class HomePage extends StatefulWidget {
class HomePageState extends State<HomePage> { class HomePageState extends State<HomePage> {
List<Account> accounts = []; List<Account> accounts = [];
String _selectedCurrency=""; String _selectedCurrency = "";
Future<String> getCurrencyFromSharedPreferences(String key) async { Future<String> getCurrencyFromSharedPreferences(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
if (prefs.getString(key)=="Euro"){ if (prefs.getString(key) == "Euro") {
_selectedCurrency=""; _selectedCurrency = "";
} }
if (prefs.getString(key)=="Dollar"){ if (prefs.getString(key) == "Dollar") {
_selectedCurrency=r"$"; _selectedCurrency = r"$";
} }
if (prefs.getString(key)=="CHF"){ if (prefs.getString(key) == "CHF") {
_selectedCurrency="CHF"; _selectedCurrency = "CHF";
} }
return prefs.getString(key) ?? 'Euro'; return prefs.getString(key) ?? 'Euro';
@ -77,9 +81,7 @@ class HomePageState extends State<HomePage> {
super.initState(); super.initState();
_themeManager.addListener(themeListener); _themeManager.addListener(themeListener);
getCurrencyFromSharedPreferences("currency").then((value) { getCurrencyFromSharedPreferences("currency").then((value) {
setState(() { setState(() {});
});
}); });
loadAccounts(); loadAccounts();
} }
@ -110,7 +112,7 @@ class HomePageState extends State<HomePage> {
Future<void> saveAccounts() async { Future<void> saveAccounts() async {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> accountJsonList = List<String> accountJsonList =
accounts.map((account) => json.encode(account.toJson())).toList(); accounts.map((account) => json.encode(account.toJson())).toList();
await prefs.setStringList('accounts', accountJsonList); await prefs.setStringList('accounts', accountJsonList);
} }
@ -134,26 +136,35 @@ class HomePageState extends State<HomePage> {
}); });
} }
Future<void> saveCurrencyToSharedPreferences(String key, String value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString(key, value);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
toolbarHeight: 70,
centerTitle: true, centerTitle: true,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
elevation: 0, elevation: 0,
title: Text( title: Text(
'title'.tr(), 'title'.tr(),
style: const TextStyle( style: TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.black54, color: Theme
), .of(context)
.brightness == Brightness.dark
? Colors.white70
: Colors.black87),
), ),
actions: [ actions: [
Padding( Padding(
padding: const EdgeInsets.only(right: 16.0, top: 2, bottom: 0), padding: const EdgeInsets.only(right: 16.0, top: 9, bottom: 0),
child: NeumorphicButton( child: NeumorphicButton(
margin: EdgeInsets.only(bottom: 10), margin: const EdgeInsets.only(bottom: 16),
onPressed: () async { onPressed: () async {
await Navigator.push( await Navigator.push(
context, context,
@ -164,67 +175,111 @@ class HomePageState extends State<HomePage> {
style: NeumorphicStyle( style: NeumorphicStyle(
shape: NeumorphicShape.convex, shape: NeumorphicShape.convex,
boxShape: const NeumorphicBoxShape.circle(), boxShape: const NeumorphicBoxShape.circle(),
depth: 6, depth: 8,
intensity: 0.9, intensity: 0.9,
color: Colors.grey.shade100, shadowLightColor:
Theme
.of(context)
.brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme
.of(context)
.shadowColor,
shadowDarkColor:
Theme
.of(context)
.brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme
.of(context)
.brightness == Brightness.light
? grey200
: grey800,
), ),
child: const Icon(Icons.settings, color: Colors.black38), child: Icon(Icons.settings,
color: Theme
.of(context)
.unselectedWidgetColor),
), ),
), ),
], ],
), ),
body: ListView.builder( body: Padding(
physics: const BouncingScrollPhysics(), padding: const EdgeInsets.only(top: 5),
itemCount: accounts.length, child: ListView.builder(
itemBuilder: (context, index) { physics: const BouncingScrollPhysics(),
return GestureDetector( itemCount: accounts.length,
onLongPress: () { itemBuilder: (context, index) {
AwesomeDialog( return GestureDetector(
btnOkText: "Delete".tr(), onLongPress: () {
btnOkColor: Colors.lightGreen, AwesomeDialog(
btnCancelColor: Colors.grey, btnOkText: "Delete".tr(),
context: context, btnOkColor: Colors.lightGreen,
animType: AnimType.bottomSlide, btnCancelColor: Theme
dialogType: DialogType.info, .of(context)
title: 'deleteaccount'.tr(), .shadowColor,
headerAnimationLoop: false, context: context,
desc: 'sure'.tr(), animType: AnimType.bottomSlide,
btnCancelOnPress: () {}, dialogType: DialogType.info,
btnOkOnPress: () { title: 'deleteaccount'.tr(),
deleteAccount(accounts[index]); headerAnimationLoop: false,
desc: 'sure'.tr(),
btnCancelOnPress: () {},
btnOkOnPress: () {
deleteAccount(accounts[index]);
},
).show();
}, },
).show(); child: Neumorphic(
}, margin: const EdgeInsets.all(16),
child: Neumorphic( style: NeumorphicStyle(
margin: const EdgeInsets.all(16), depth: 8,
style: NeumorphicStyle( intensity: 1,
depth: 7, shadowLightColor:
intensity: 1, Theme
shadowDarkColor: Colors.grey.shade300, .of(context)
color: Colors.grey.shade100, .brightness == Brightness.light
boxShape: ? const NeumorphicStyle().shadowLightColor
: grey800,
shadowDarkColor:
Theme
.of(context)
.brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: Theme
.of(context)
.shadowColor,
color: Theme
.of(context)
.brightness == Brightness.light
? grey200
: grey800,
boxShape:
NeumorphicBoxShape.roundRect(BorderRadius.circular(15)), NeumorphicBoxShape.roundRect(BorderRadius.circular(15)),
), ),
child: ListTile( child: ListTile(
title: Text(accounts[index].name), title: Text(accounts[index].name),
subtitle: Text( subtitle: Text(
'${'balance'.tr()}: $_selectedCurrency${accounts[index].balance.toStringAsFixed(2)}'), '${'balance'.tr()}: $_selectedCurrency${accounts[index]
onTap: () { .balance.toStringAsFixed(2)}'),
Navigator.push( onTap: () {
context, Navigator.push(
MaterialPageRoute( context,
builder: (context) => AccountDetailPage( MaterialPageRoute(
account: accounts[index], builder: (context) =>
updateAccountBalance: updateAccountBalance, AccountDetailPage(
), account: accounts[index],
), updateAccountBalance: updateAccountBalance,
); ),
}, ),
), );
), },
); ),
}, ),
), );
},
)),
floatingActionButton: NeumorphicButton( floatingActionButton: NeumorphicButton(
onPressed: () { onPressed: () {
showDialog( showDialog(
@ -239,14 +294,33 @@ class HomePageState extends State<HomePage> {
style: NeumorphicStyle( style: NeumorphicStyle(
depth: 8, depth: 8,
intensity: 1, intensity: 1,
shadowDarkColor: Colors.grey.shade400, shadowLightColor: Theme
color: Colors.grey.shade100, .of(context)
.brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme
.of(context)
.shadowColor,
shadowDarkColor: Theme
.of(context)
.brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme
.of(context)
.brightness == Brightness.light
? grey200
: grey800,
boxShape: const NeumorphicBoxShape.circle(), boxShape: const NeumorphicBoxShape.circle(),
), ),
child: const Icon( child: Icon(
Icons.add, Icons.add,
size: 60, size: 60,
color: Colors.black12, color: Theme
.of(context)
.brightness == Brightness.light
? Colors.black12
: Colors.white12,
), ),
), ),
); );

View File

@ -1,11 +1,11 @@
import 'dart:async'; import 'dart:async';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_neumorphic/flutter_neumorphic.dart'; import 'package:flutter_neumorphic/flutter_neumorphic.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:tests/theme/theme_constants.dart';
import 'package:tests/theme/theme_manager.dart'; import 'package:tests/theme/theme_manager.dart';
import 'main.dart'; import 'main.dart';
ThemeManager _themeManager = ThemeManager(); ThemeManager _themeManager = ThemeManager();
@ -50,6 +50,11 @@ class SettingsState extends State<Settings> {
await prefs.setString(key, value); await prefs.setString(key, value);
} }
Future<void> saveThemeToSharedPreferences(String key, bool value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setBool(key, value);
}
Future<String> getCurrencyFromSharedPreferences(String key) async { Future<String> getCurrencyFromSharedPreferences(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getString(key) ?? 'Euro'; return prefs.getString(key) ?? 'Euro';
@ -84,11 +89,12 @@ class SettingsState extends State<Settings> {
toolbarHeight: 80, toolbarHeight: 80,
title: Text( title: Text(
'settings'.tr(), 'settings'.tr(),
style: const TextStyle( style: TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.black54, color: Theme.of(context).brightness == Brightness.dark
), ? Colors.white70
: Colors.black87),
), ),
centerTitle: true, centerTitle: true,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
@ -97,13 +103,14 @@ class SettingsState extends State<Settings> {
bottomRight: Radius.circular(15), bottomRight: Radius.circular(15),
), ),
), ),
shadowColor: Colors.grey.shade300, shadowColor: Theme.of(context).shadowColor,
leading: Padding( leading: Padding(
padding: const EdgeInsets.only(left: 16.0), padding: const EdgeInsets.only(left: 16.0),
child: NeumorphicButton( child: NeumorphicButton(
onPressed: () { onPressed: () {
Navigator.pop(context); // Zurück zur vorherigen Seite Navigator.pop(context); // Zurück zur vorherigen Seite
Navigator.pushReplacement( // Neue Seite öffnen und vorherige Seite ersetzen Navigator.pushReplacement(
// Neue Seite öffnen und vorherige Seite ersetzen
context, context,
MaterialPageRoute(builder: (context) => const HomePage()), MaterialPageRoute(builder: (context) => const HomePage()),
); );
@ -111,12 +118,21 @@ class SettingsState extends State<Settings> {
style: NeumorphicStyle( style: NeumorphicStyle(
shape: NeumorphicShape.flat, shape: NeumorphicShape.flat,
boxShape: const NeumorphicBoxShape.circle(), boxShape: const NeumorphicBoxShape.circle(),
depth: 6, depth: 7,
intensity: 0.9, intensity: 0.9,
color: Colors.grey.shade100, shadowLightColor: Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
), ),
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(8),
child: const Icon(Icons.arrow_back, color: Colors.black38), child: Icon(Icons.arrow_back,
color: Theme.of(context).unselectedWidgetColor),
), ),
), ),
), ),
@ -127,38 +143,57 @@ class SettingsState extends State<Settings> {
style: NeumorphicStyle( style: NeumorphicStyle(
depth: 7, depth: 7,
intensity: 1, intensity: 1,
shadowDarkColor: Colors.grey.shade300, shadowLightColor: Theme.of(context).brightness == Brightness.light
color: Colors.grey.shade100, ? const NeumorphicStyle().shadowLightColor
: grey800,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: Theme.of(context).shadowColor,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(15)), boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(15)),
), ),
child: ListTile( child: ListTile(
title: Text('darkmode'.tr()), title: Text('darkmode'.tr()),
trailing: NeumorphicSwitch( trailing:
value: _themeManager.themeMode == ThemeMode.dark, Consumer<ThemeManager>(builder: (context, themeManager, _) {
onChanged: (bool value) { return NeumorphicSwitch(
setState(() { value: themeManager.themeMode == ThemeMode.dark,
_themeManager.toggleTheme(value); onChanged: (bool value) {
}); setState(() {
}, themeManager.toggleTheme(value);
style: NeumorphicSwitchStyle( });
lightSource: LightSource.topLeft, },
thumbShape: NeumorphicShape.concave, style: NeumorphicSwitchStyle(
trackDepth: 5, lightSource: LightSource.topLeft,
activeTrackColor: Colors.lightGreen, thumbShape: NeumorphicShape.concave,
inactiveTrackColor: Colors.grey.shade300, trackDepth: 5,
activeThumbColor: Colors.grey.shade100, activeTrackColor: Colors.lightGreen,
inactiveThumbColor: Colors.grey.shade200, inactiveTrackColor: Theme.of(context).shadowColor,
), activeThumbColor:
), Theme.of(context).brightness == Brightness.light
), ? grey200
: grey800,
inactiveThumbColor: Theme.of(context).shadowColor,
),
);
})),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
Neumorphic( Neumorphic(
style: NeumorphicStyle( style: NeumorphicStyle(
depth: 7, depth: 7,
intensity: 1, intensity: 1,
shadowDarkColor: Colors.grey.shade300, shadowLightColor: Theme.of(context).brightness == Brightness.light
color: Colors.grey.shade100, ? const NeumorphicStyle().shadowLightColor
: grey800,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: Theme.of(context).shadowColor,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(15)), boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(15)),
), ),
child: ListTile( child: ListTile(
@ -196,8 +231,15 @@ class SettingsState extends State<Settings> {
style: NeumorphicStyle( style: NeumorphicStyle(
depth: 7, depth: 7,
intensity: 1, intensity: 1,
shadowDarkColor: Colors.grey.shade300, shadowLightColor: Theme.of(context).brightness == Brightness.light
color: Colors.grey.shade100, ? const NeumorphicStyle().shadowLightColor
: grey800,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: Theme.of(context).shadowColor,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(15)), boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(15)),
), ),
child: ListTile( child: ListTile(
@ -211,10 +253,12 @@ class SettingsState extends State<Settings> {
onChanged: (String? newValue) { onChanged: (String? newValue) {
setState(() { setState(() {
_selectedCurrency = newValue!; _selectedCurrency = newValue!;
saveCurrencyToSharedPreferences("currency", _selectedCurrency); saveCurrencyToSharedPreferences(
"currency", _selectedCurrency);
}); });
}, },
items: _currencies.map<DropdownMenuItem<String>>((String value) { items:
_currencies.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>( return DropdownMenuItem<String>(
value: value, value: value,
child: Text(value), child: Text(value),

View File

@ -1,24 +1,26 @@
import 'package:carousel_slider/carousel_slider.dart'; import 'package:carousel_slider/carousel_slider.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_neumorphic/flutter_neumorphic.dart'; import 'package:flutter_neumorphic/flutter_neumorphic.dart';
import 'package:tests/theme/theme_constants.dart';
class SavingsTipsDialog extends StatelessWidget { class SavingsTipsDialog extends StatelessWidget {
final List<String> savingsTips = [ final List<String> savingsTips = [
'Spare jeden Monat einen festen Betrag.', 'tip1'.tr(),
'Vergleiche Preise, bevor du etwas kaufst.', 'tip2'.tr(),
'Vermeide unnötige Ausgaben.', 'tip3'.tr(),
'Setze dir konkrete Sparziele.', 'tip4'.tr(),
'Überprüfe regelmäßig deine Ausgaben.', 'tip5'.tr(),
'Verkaufe Dinge, die du nicht mehr brauchst.', 'tip6'.tr(),
'Nutze Cashback-Programme beim Einkaufen.', 'tip7'.tr(),
'Koche selbst anstatt auswärts zu essen.', 'tip8'.tr(),
'Nutze kostenlose Angebote und Gutscheine.', 'tip9'.tr(),
'Vermeide Impulskäufe und schlafe vor größeren Ausgaben eine Nacht darüber.', 'tip10'.tr(),
'Fahre mit dem Fahrrad oder öffentlichen Verkehrsmitteln anstatt mit dem Auto.', 'tip11'.tr(),
'Plane deine Mahlzeiten im Voraus, um Lebensmittelverschwendung zu vermeiden.', 'tip12'.tr(),
'Vergleiche Versicherungen und Verträge, um Geld zu sparen.', 'tip13'.tr(),
'Mache deine eigenen Reinigungsmittel statt teure Produkte zu kaufen.', 'tip14'.tr(),
'Nutze kostenlose Online-Ressourcen für Weiterbildung und Hobbys.', 'tip15'.tr(),
]; ];
SavingsTipsDialog({super.key}); SavingsTipsDialog({super.key});
@ -38,30 +40,40 @@ class SavingsTipsDialog extends StatelessWidget {
itemCount: savingsTips.length, itemCount: savingsTips.length,
itemBuilder: (BuildContext context, int index, int realIndex) { itemBuilder: (BuildContext context, int index, int realIndex) {
return Neumorphic( return Neumorphic(
margin: const EdgeInsets.only(bottom: 5), margin: const EdgeInsets.fromLTRB(0, 11, 0, 7),
style: NeumorphicStyle( style: NeumorphicStyle(
boxShape: NeumorphicBoxShape.roundRect( shadowLightColor:
BorderRadius.circular(13.0)), Theme.of(context).brightness == Brightness.light
), ? const NeumorphicStyle().shadowLightColor
child: Container( : Theme.of(context).shadowColor,
decoration: BoxDecoration( shadowDarkColor:
Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
boxShape: NeumorphicBoxShape.roundRect(
BorderRadius.circular(13.0)),
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
color: Colors.grey color: Theme.of(context).brightness == Brightness.dark
.shade100, // Setze die Hintergrundfarbe auf rot ? grey700
), : grey200),
padding: const EdgeInsets.all(14.0), padding: const EdgeInsets.all(14.0),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
savingsTips[index], savingsTips[index],
style: const TextStyle(fontSize: 18.0), style: const TextStyle(fontSize: 18.0),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
], ],
),
), ),
),
); );
}, },
options: CarouselOptions( options: CarouselOptions(
@ -83,14 +95,26 @@ class SavingsTipsDialog extends StatelessWidget {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
style: NeumorphicStyle( style: NeumorphicStyle(
color: Colors.grey.shade100, shadowLightColor:
Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
depth: 10, depth: 10,
intensity: 0.9, intensity: 0.9,
shape: NeumorphicShape.flat, shape: NeumorphicShape.flat,
boxShape: boxShape:
NeumorphicBoxShape.roundRect(BorderRadius.circular(15.0)), NeumorphicBoxShape.roundRect(BorderRadius.circular(15.0)),
), ),
child: Text('close'.tr()), child: Text(
'close'.tr(),
style: TextStyle(color: Theme.of(context).cardColor),
),
), ),
], ],
), ),

View File

@ -1,17 +1,66 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
const COLOR_PRIMARY = Colors.deepOrangeAccent; final grey200=Colors.grey[200];
final grey300=Colors.grey[300];
ThemeData lightTheme = ThemeData( final grey400=Colors.grey[400];
brightness: Brightness.light, final grey700=Colors.grey[700];
primaryColor: COLOR_PRIMARY, final grey800=Colors.grey[800];
fontFamily: "Montserrat"); final grey600=Colors.grey[600];
final ThemeData lightTheme = ThemeData(
ThemeData darkTheme = ThemeData( scaffoldBackgroundColor: Colors.grey[100],
fontFamily: "Montserrat", textTheme: const TextTheme(
brightness: Brightness.dark, displayLarge:(TextStyle(color: Colors.black87)),
switchTheme: SwitchThemeData( displayMedium: (TextStyle(color: Colors.black87)),
trackColor: MaterialStateProperty.all<Color>(Colors.grey), displaySmall:(TextStyle(color: Colors.black87)),
thumbColor: MaterialStateProperty.all<Color>(Colors.white), labelLarge:(TextStyle(color: Colors.black87)),
labelMedium:(TextStyle(color: Colors.black87)),
labelSmall:(TextStyle(color: Colors.black87)),
headlineLarge:(TextStyle(color: Colors.black87)),
headlineMedium:(TextStyle(color: Colors.black87)),
headlineSmall:(TextStyle(color: Colors.black87)),
titleLarge:(TextStyle(color: Colors.black87)),
titleMedium:(TextStyle(color: Colors.black87)),
titleSmall:(TextStyle(color: Colors.black87)),
bodyLarge: (TextStyle(color: Colors.black54)),
bodyMedium:(TextStyle(color: Colors.black54)),
bodySmall: (TextStyle(color: Colors.black54))
), ),
brightness: Brightness.light,
shadowColor: Colors.grey[300],
cardColor: Colors.black87,
unselectedWidgetColor: Colors.black54,
fontFamily: "Montserrat",
buttonTheme: ButtonThemeData(
buttonColor: Colors.grey[100],
textTheme: ButtonTextTheme.primary
),
); );
final ThemeData darkTheme = ThemeData(
textTheme: const TextTheme(
displayLarge:(TextStyle(color: Colors.white70)),
displayMedium: (TextStyle(color: Colors.white70)),
displaySmall:(TextStyle(color: Colors.white70)),
labelLarge:(TextStyle(color: Colors.white70)),
labelMedium:(TextStyle(color: Colors.white70)),
labelSmall:(TextStyle(color: Colors.white70)),
headlineLarge:(TextStyle(color: Colors.white70)),
headlineMedium:(TextStyle(color: Colors.white70)),
headlineSmall:(TextStyle(color: Colors.white70)),
titleLarge:(TextStyle(color: Colors.white70)),
titleMedium:(TextStyle(color: Colors.white70)),
titleSmall:(TextStyle(color: Colors.white70)),
bodyLarge: (TextStyle(color: Colors.white54)),
bodyMedium:(TextStyle(color: Colors.white54)),
bodySmall: (TextStyle(color: Colors.white54)),
),
shadowColor: Colors.grey[700],
fontFamily: "Montserrat",
cardColor: Colors.white70,
unselectedWidgetColor: Colors.white54,
brightness: Brightness.dark,
buttonTheme: ButtonThemeData(
buttonColor: Colors.grey[900],
),
);

View File

@ -1,14 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ThemeManager with ChangeNotifier{ class ThemeManager with ChangeNotifier {
ThemeMode _themeMode = ThemeMode.light; ThemeMode _themeMode = ThemeMode.light;
get themeMode => _themeMode; ThemeMode get themeMode => _themeMode;
toggleTheme(bool isDark){ void toggleTheme(bool isDark) {
_themeMode = isDark?ThemeMode.dark:ThemeMode.light; _themeMode = isDark ? ThemeMode.dark : ThemeMode.light;
notifyListeners(); notifyListeners();
}
}
} }

View File

@ -1,9 +1,11 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_neumorphic/flutter_neumorphic.dart'; import 'package:flutter_neumorphic/flutter_neumorphic.dart';
import 'package:tests/transaction/transaction.dart'; import 'package:tests/transaction/transaction.dart';
import '../theme/theme_constants.dart';
class AddTransactionDialog extends StatefulWidget { class AddTransactionDialog extends StatefulWidget {
final Function addTransaction; final Function addTransaction;
const AddTransactionDialog({super.key, required this.addTransaction}); const AddTransactionDialog({super.key, required this.addTransaction});
@override @override
@ -48,11 +50,10 @@ class AddTransactionDialogState extends State<AddTransactionDialog> {
'addtrans'.tr(), 'addtrans'.tr(),
style: const TextStyle( style: const TextStyle(
fontSize: 20, fontSize: 20,
color: Colors.black54,
), ),
), ),
content: Form( content: Form(
key: _formKey, // Hier wird das _formKey dem Form-Widget zugewiesen key: _formKey, //
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -60,7 +61,17 @@ class AddTransactionDialogState extends State<AddTransactionDialog> {
style: NeumorphicStyle( style: NeumorphicStyle(
depth: -5, depth: -5,
intensity: 0.8, intensity: 0.8,
color: Colors.grey.shade100, shadowLightColor:
Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor:
Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
boxShape: NeumorphicBoxShape.roundRect( boxShape: NeumorphicBoxShape.roundRect(
BorderRadius.circular(12), BorderRadius.circular(12),
), ),
@ -88,7 +99,17 @@ class AddTransactionDialogState extends State<AddTransactionDialog> {
style: NeumorphicStyle( style: NeumorphicStyle(
depth: -5, depth: -5,
intensity: 0.8, intensity: 0.8,
color: Colors.grey.shade100, shadowLightColor:
Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor:
Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
boxShape: NeumorphicBoxShape.roundRect( boxShape: NeumorphicBoxShape.roundRect(
BorderRadius.circular(12), BorderRadius.circular(12),
), ),
@ -121,7 +142,10 @@ class AddTransactionDialogState extends State<AddTransactionDialog> {
NeumorphicCheckbox( NeumorphicCheckbox(
style: NeumorphicCheckboxStyle( style: NeumorphicCheckboxStyle(
selectedColor: Colors.lightGreen, selectedColor: Colors.lightGreen,
disabledColor: Colors.grey.shade200, disabledColor:
Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
selectedDepth: -10, selectedDepth: -10,
unselectedDepth: 8), unselectedDepth: 8),
value: _isExpense, value: _isExpense,
@ -134,7 +158,6 @@ class AddTransactionDialogState extends State<AddTransactionDialog> {
const SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
'expense'.tr(), 'expense'.tr(),
style: const TextStyle(color: Colors.black87),
), ),
], ],
), ),
@ -152,7 +175,15 @@ class AddTransactionDialogState extends State<AddTransactionDialog> {
boxShape: NeumorphicBoxShape.roundRect( boxShape: NeumorphicBoxShape.roundRect(
BorderRadius.circular(12), BorderRadius.circular(12),
), ),
color: Colors.grey.shade100, shadowLightColor: Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
), ),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
child: Text( child: Text(
@ -164,6 +195,7 @@ class AddTransactionDialogState extends State<AddTransactionDialog> {
), ),
), ),
NeumorphicButton( NeumorphicButton(
margin: const EdgeInsets.fromLTRB(0, 0, 4, 4),
onPressed: _submitForm, onPressed: _submitForm,
style: NeumorphicStyle( style: NeumorphicStyle(
shape: NeumorphicShape.concave, shape: NeumorphicShape.concave,
@ -172,7 +204,15 @@ class AddTransactionDialogState extends State<AddTransactionDialog> {
boxShape: NeumorphicBoxShape.roundRect( boxShape: NeumorphicBoxShape.roundRect(
BorderRadius.circular(12), BorderRadius.circular(12),
), ),
color: Colors.grey.shade100, shadowLightColor: Theme.of(context).brightness == Brightness.light
? const NeumorphicStyle().shadowLightColor
: Theme.of(context).shadowColor,
shadowDarkColor: Theme.of(context).brightness == Brightness.dark
? const NeumorphicStyle().shadowDarkColor
: grey400,
color: Theme.of(context).brightness == Brightness.light
? grey200
: grey800,
), ),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
child: Text( child: Text(

View File

@ -261,6 +261,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.8.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
path: path:
dependency: transitive dependency: transitive
description: description:
@ -333,6 +341,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.2.4" version: "4.2.4"
provider:
dependency: "direct main"
description:
name: provider
sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
url: "https://pub.dev"
source: hosted
version: "6.0.5"
rive: rive:
dependency: transitive dependency: transitive
description: description:

View File

@ -44,6 +44,7 @@ dependencies:
flutter_svg: ^2.0.0 flutter_svg: ^2.0.0
circular_seek_bar: ^1.1.0 circular_seek_bar: ^1.1.0
tab_indicator_styler: ^2.0.0 tab_indicator_styler: ^2.0.0
provider: ^6.0.5
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: