import 'package:flutter/material.dart'; import 'package:flutter_picker_plus/picker.dart'; import 'package:get_it/get_it.dart'; import 'package:okane/database/collections/account.dart'; import 'package:okane/database/collections/beneficiary.dart'; import 'package:okane/database/collections/recurrent.dart'; import 'package:okane/database/collections/template.dart'; import 'package:okane/database/database.dart'; import 'package:okane/ui/state/core.dart'; import 'package:okane/ui/transaction.dart'; import 'package:okane/ui/utils.dart'; import 'package:searchfield/searchfield.dart'; enum Period { days, weeks, months, years } class AddRecurringTransactionTemplateWidget extends StatefulWidget { final VoidCallback onAdd; final Account activeAccountItem; const AddRecurringTransactionTemplateWidget({ super.key, required this.activeAccountItem, required this.onAdd, }); @override State createState() => _AddRecurringTransactionTemplateWidgetState(); } class _AddRecurringTransactionTemplateWidgetState extends State { final TextEditingController _beneficiaryTextController = TextEditingController(); final TextEditingController _amountTextController = TextEditingController(); final TextEditingController _templateNameController = TextEditingController(); List beneficiaries = []; SearchFieldListItem? _selectedBeneficiary; TransactionDirection _selectedDirection = TransactionDirection.send; Period _selectedPeriod = Period.months; int _periodSize = 1; String getBeneficiaryName(Beneficiary item) { return switch (item.type) { BeneficiaryType.account => "${item.name} (Account)", BeneficiaryType.other => item.name, }; } Future _submit(BuildContext context) async { final beneficiaryName = _beneficiaryTextController.text; if (_selectedBeneficiary == null && beneficiaryName.isEmpty) { return; } if (_templateNameController.text.isEmpty) { return; } Beneficiary? beneficiary = _selectedBeneficiary?.item; if (beneficiary == null || getBeneficiaryName(beneficiary) != beneficiaryName) { // Add a new beneficiary, if none was selected final result = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text("Add Beneficiary"), content: Text( "The beneficiary '$beneficiaryName' does not exist. Do you want to add it?", ), actions: [ TextButton( style: TextButton.styleFrom( textStyle: Theme.of(context).textTheme.labelLarge, ), child: const Text('Add'), onPressed: () => Navigator.of(context).pop(true), ), TextButton( style: TextButton.styleFrom( textStyle: Theme.of(context).textTheme.labelLarge, ), child: const Text('Cancel'), onPressed: () => Navigator.of(context).pop(false), ), ], ), ); if (result == null || !result) { return; } beneficiary = Beneficiary() ..name = beneficiaryName ..type = BeneficiaryType.other; await upsertBeneficiary(beneficiary); } final days = switch (_selectedPeriod) { Period.days => _periodSize, Period.weeks => _periodSize * 7, Period.months => _periodSize * 31, Period.years => _periodSize * 365, }; final factor = switch (_selectedDirection) { TransactionDirection.send => -1, TransactionDirection.receive => 1, }; final amount = factor * double.parse(_amountTextController.text).abs(); final template = TransactionTemplate() ..name = _templateNameController.text ..beneficiary.value = beneficiary ..account.value = widget.activeAccountItem ..recurring = true ..amount = amount; await upsertTransactionTemplate(template); final transaction = RecurringTransaction() ..lastExecution = null ..template.value = template ..account.value = widget.activeAccountItem ..days = days; await upsertRecurringTransaction(transaction); _periodSize = 1; _selectedPeriod = Period.weeks; _amountTextController.text = ""; _templateNameController.text = ""; widget.onAdd(); } @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: ListView( shrinkWrap: true, children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: TextField( controller: _templateNameController, decoration: InputDecoration(label: Text("Template name")), ), ), Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: SearchField( suggestions: beneficiaries .where((el) { final bloc = GetIt.I.get(); if (el.type == BeneficiaryType.account) { return el.account.value?.id != bloc.activeAccount?.id; } return true; }) .map((el) { return SearchFieldListItem( getBeneficiaryName(el), item: el, ); }) .toList(), hint: "Beneficiary", controller: _beneficiaryTextController, selectedValue: _selectedBeneficiary, onSuggestionTap: (beneficiary) { setState(() => _selectedBeneficiary = beneficiary); }, ), ), Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: TextField( controller: _amountTextController, keyboardType: TextInputType.numberWithOptions( signed: false, decimal: false, ), decoration: InputDecoration(hintText: "Amount"), ), ), Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: SegmentedButton( segments: [ ButtonSegment( value: TransactionDirection.send, label: Text("Send"), icon: Icon(Icons.remove), ), ButtonSegment( value: TransactionDirection.receive, label: Text("Receive"), icon: Icon(Icons.add), ), ], selected: {_selectedDirection}, multiSelectionEnabled: false, onSelectionChanged: (selection) { setState(() => _selectedDirection = selection.first); }, ), ), Padding( padding: EdgeInsets.only(left: 16, right: 16, top: 16), child: SegmentedButton( segments: [ ButtonSegment(value: Period.days, label: Text("Days")), ButtonSegment(value: Period.weeks, label: Text("Weeks")), ButtonSegment(value: Period.months, label: Text("Months")), ButtonSegment(value: Period.years, label: Text("Years")), ], selected: {_selectedPeriod}, multiSelectionEnabled: false, onSelectionChanged: (selection) { setState(() => _selectedPeriod = selection.first); }, ), ), Text.rich( TextSpan( text: "Repeat every ", children: [ WidgetSpan( child: TextButton( onPressed: () { Picker( adapter: NumberPickerAdapter( data: [ NumberPickerColumn( begin: 1, end: 999, initValue: _periodSize, ), ], ), hideHeader: true, selectedTextStyle: TextStyle(color: Colors.blue), onConfirm: (Picker picker, List value) { setState(() { _periodSize = (value.first as int) + 1; }); }, ).showDialog(context); }, child: Text(_periodSize.toString()), ), ), TextSpan( text: switch (_selectedPeriod) { Period.days => " days", Period.weeks => " weeks", Period.months => " months", Period.years => " years", }, ), ], ), ), Align( alignment: Alignment.centerRight, child: OutlinedButton( onPressed: () => _submit(context), child: Text("Add"), ), ), ], ), ); } }