import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:intl/intl.dart'; import 'package:prasule/api/category.dart'; import 'package:prasule/api/entry_data.dart'; import 'package:prasule/api/recurring_entry.dart'; import 'package:prasule/api/wallet.dart'; import 'package:prasule/api/wallet_manager.dart'; import 'package:prasule/main.dart'; import 'package:prasule/pw/platformbutton.dart'; import 'package:prasule/pw/platformfield.dart'; import 'package:prasule/util/text_color.dart'; /// Used when user wants to add new entry class CreateRecurringEntryView extends StatefulWidget { /// Used when user wants to add new entry const CreateRecurringEntryView({ required this.w, required this.locale, super.key, this.editEntry, }); /// The wallet, where the entry will be saved to final Wallet w; /// Entry we want to edit /// /// Is null unless we are editing an existing entry final RecurringWalletEntry? editEntry; /// Selected locale final String locale; @override State createState() => _CreateRecurringEntryViewState(); } class _CreateRecurringEntryViewState extends State { late RecurringWalletEntry newEntry; @override void initState() { super.initState(); if (widget.editEntry != null) { newEntry = widget.editEntry!; } else { newEntry = RecurringWalletEntry( id: widget.w.nextId, data: EntryData(amount: 0, name: ""), type: EntryType.expense, date: DateTime.now(), category: widget.w.categories.first, lastRunDate: DateTime.now(), recurType: RecurType.month, ); } setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(AppLocalizations.of(context).createEntry), ), body: SizedBox( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, child: Center( child: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: MediaQuery.of(context).size.width * 0.8, child: PlatformField( labelText: AppLocalizations.of(context).name, controller: TextEditingController(text: newEntry.data.name), onChanged: (v) { newEntry.data.name = v; }, ), ), const SizedBox( height: 15, ), SizedBox( width: MediaQuery.of(context).size.width * 0.8, child: PlatformField( labelText: AppLocalizations.of(context).amount, controller: TextEditingController( text: newEntry.data.amount.toString(), ), keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ FilteringTextInputFormatter.allow( RegExp(r'\d+[\.,]{0,1}\d{0,}'), ), ], onChanged: (v) { logger.i(v); newEntry.data.amount = double.parse(v); }, ), ), const SizedBox( height: 20, ), Text(AppLocalizations.of(context).type), const SizedBox( height: 10, ), SizedBox( width: MediaQuery.of(context).size.width * 0.8, child: DropdownButton( value: newEntry.type, items: [ DropdownMenuItem( value: EntryType.expense, child: SizedBox( width: MediaQuery.of(context).size.width * 0.8 - 24, child: Text( AppLocalizations.of(context).expense, ), ), ), DropdownMenuItem( value: EntryType.income, child: SizedBox( width: MediaQuery.of(context).size.width * 0.8 - 24, child: Text(AppLocalizations.of(context).income), ), ), ], onChanged: (v) { if (v == null) return; newEntry.type = v; setState(() {}); }, ), ), const SizedBox( height: 20, ), Text(AppLocalizations.of(context).category), const SizedBox( height: 10, ), SizedBox( width: MediaQuery.of(context).size.width * 0.8, child: DropdownButton( value: newEntry.category.id, items: List.generate( widget.w.categories.length, (index) => DropdownMenuItem( value: widget.w.categories[index].id, child: SizedBox( width: MediaQuery.of(context).size.width * 0.8 - 24, child: Text( widget.w.categories[index].name, ), ), ), ), onChanged: (v) { if (v == null) return; newEntry.category = widget.w.categories .where((element) => element.id == v) .first; setState(() {}); }, ), ), const SizedBox( height: 20, ), Text(AppLocalizations.of(context).description), const SizedBox( height: 10, ), ConstrainedBox( constraints: BoxConstraints( minWidth: MediaQuery.of(context).size.width * 0.8, maxWidth: MediaQuery.of(context).size.width * 0.8, maxHeight: 300, ), child: PlatformField( keyboardType: TextInputType.multiline, maxLines: null, controller: TextEditingController( text: newEntry.data.description, ), onChanged: (v) { newEntry.data.description = v; }, ), ), const SizedBox( height: 20, ), SizedBox( width: MediaQuery.of(context).size.width * 0.9, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( AppLocalizations.of(context) .recurEvery(newEntry.repeatAfter), ), const SizedBox( width: 10, ), SizedBox( width: 50, child: PlatformField( controller: TextEditingController( text: newEntry.repeatAfter.toString(), ), inputFormatters: [ FilteringTextInputFormatter.digitsOnly, FilteringTextInputFormatter.deny( RegExp(r"^0$"), replacementString: "1", ), ], onChanged: (s) { final n = int.tryParse(s); if (n == null) return; newEntry.repeatAfter = n; setState(() {}); }, ), ), ], ), ), SizedBox( width: 200, child: DropdownButton( value: newEntry.recurType, items: [ DropdownMenuItem( value: RecurType.day, child: SizedBox( width: 176, child: Text( AppLocalizations.of(context) .dayCounter(newEntry.repeatAfter), ), ), ), DropdownMenuItem( value: RecurType.month, child: SizedBox( width: 176, child: Text( AppLocalizations.of(context) .monthCounter(newEntry.repeatAfter), ), ), ), DropdownMenuItem( value: RecurType.year, child: SizedBox( width: 176, child: Text( AppLocalizations.of(context) .yearCounter(newEntry.repeatAfter), ), ), ), ], onChanged: (v) { if (v == null) return; newEntry.recurType = v; setState(() {}); }, ), ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(AppLocalizations.of(context).startingWithDate), const SizedBox( width: 10, ), // TODO: maybe use sizedbox on row with spaceEvenly? PlatformButton( text: DateFormat.yMMMMd(widget.locale) .format(newEntry.lastRunDate), style: (widget.editEntry != null) ? ButtonStyle( backgroundColor: MaterialStateProperty.all( Colors.grey.harmonizeWith( Theme.of(context).colorScheme.primary, ), ), foregroundColor: MaterialStateProperty.all( Colors.grey .harmonizeWith( Theme.of(context).colorScheme.primary, ) .calculateTextColor() .harmonizeWith( Theme.of(context).colorScheme.primary), ), ) : null, onPressed: () async { if (widget.editEntry != null) { return; // disabled on edit } final d = await showDatePicker( context: context, firstDate: DateTime.now(), lastDate: DateTime.now().add(const Duration(days: 365)), ); if (d == null) return; newEntry.lastRunDate = d; setState(() {}); }, ), ], ), const SizedBox( height: 15, ), PlatformButton( text: AppLocalizations.of(context).save, onPressed: () { if (newEntry.data.name.isEmpty) { ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(AppLocalizations.of(context).errorEmptyName), ), ); return; } if (widget.editEntry != null) { Navigator.of(context).pop(newEntry); return; } widget.w.recurringEntries.add(newEntry); WalletManager.saveWallet(widget.w).then( (value) => Navigator.of(context).pop(widget.w), ); // TODO loading circle? }, ), ], ), ), ), ), ); } }