import 'dart:typed_data'; import 'package:alert_dialog/alert_dialog.dart'; import 'package:confirm_dialog/confirm_dialog.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_pdfview/flutter_pdfview.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:logging/logging.dart'; import 'package:moneymgr_mobile/services/storage/expenses.dart'; import 'package:moneymgr_mobile/services/storage/prefs.dart'; import 'package:moneymgr_mobile/utils/extensions.dart'; import 'package:moneymgr_mobile/utils/time_utils.dart'; class ExpenseEditor extends HookConsumerWidget { final Uint8List file; final Function(BaseExpenseInfo) onFinished; final Function()? onRescan; const ExpenseEditor({ super.key, required this.file, required this.onFinished, required this.onRescan, }); @override Widget build(BuildContext context, WidgetRef ref) { final serverConfig = ref.watch(prefsProvider).requireValue.serverConfig()!; final labelController = useTextEditingController(); final costController = useTextEditingController(); final timeController = useState(DateTime.now()); // Pick a new date handlePickDate() async { final date = await showDatePicker( context: context, firstDate: DateTime(2000), lastDate: DateTime(2099), initialDate: timeController.value, ); if (date != null) timeController.value = date; } // Save expense handleSubmit() async { if (costController.text.isEmpty) { context.showTextSnackBar("Please specify expense cost!"); return; } onFinished( BaseExpenseInfo( label: labelController.text, cost: int.tryParse(costController.text) ?? 0, time: timeController.value, ), ); } // Cancel operation handleRescan() async { if (await confirm( context, content: Text("Do you really want to discard this expense?"), ) && onRescan != null) { onRescan!(); } } return Scaffold( appBar: AppBar( title: Text("Expense info"), actions: [ // Rescan expense IconButton( onPressed: onRescan == null ? null : handleRescan, icon: Icon(Icons.restart_alt), ), // Submit IconButton(onPressed: handleSubmit, icon: Icon(Icons.save)), ], ), body: Column( children: [ // Expense preview Expanded( child: PDFView( pdfData: file, onError: (e) { Logger.root.warning("Failed to render PDF $e"); alert(context, content: Text("Failed to render PDF $e")); }, fitPolicy: FitPolicy.BOTH, ), ), SizedBox(height: 10), // Cost TextField( controller: costController, keyboardType: TextInputType.number, decoration: const InputDecoration(labelText: 'Cost'), textInputAction: TextInputAction.done, ), SizedBox(height: 10), // Date TextField( enabled: true, readOnly: true, controller: TextEditingController( text: timeController.value.simpleDate, ), keyboardType: TextInputType.datetime, decoration: InputDecoration( labelText: 'Date', suffixIcon: IconButton( onPressed: handlePickDate, icon: const Icon(Icons.date_range), ), ), ), SizedBox(height: 10), // Label TextField( controller: labelController, keyboardType: TextInputType.text, decoration: const InputDecoration(labelText: 'Label'), textInputAction: TextInputAction.done, maxLength: serverConfig.constraints.inbox_entry_label.max, ), ], ), ); } }