import 'package:flutter/material.dart'; import 'package:local_spend/common/platform/platform_scaffold.dart'; import 'package:intl/intl.dart'; import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:local_spend/common/widgets/animatedGradientButton.dart'; import 'package:local_spend/common/apifunctions/find_organisations.dart'; import 'package:local_spend/common/widgets/organisations_dialog.dart'; import 'package:local_spend/common/apifunctions/submit_receipt_api.dart'; import 'package:local_spend/common/apifunctions/categories.dart'; class Transaction { Transaction( this.date, this.amount, this.organisation, this.recurring, this.isEssential, this.category, ); DateTime date; TextEditingController amount; Organisation organisation; String recurring; bool isEssential; String category; } class ReceiptPage2 extends StatefulWidget { @override State createState() { return new ReceiptPage2State(); } } class ReceiptPage2State extends State { Transaction transaction = new Transaction( DateTime.now(), new TextEditingController(), new Organisation(null, null, null, null, null), "None", false, "Uncategorised", ); AlertDialog _invalidDialog(context) { return AlertDialog( title: new Text("Invalid data"), content: new Text( "We couldn't process your request because some of the data entered is invalid."), actions: [ new FlatButton( child: new Text("OK"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); } Future> getCats() async { return await getCategories(); } void _submitReceipt(Transaction transaction) { Receipt receipt = new Receipt(); receipt.organisationName = transaction.organisation.name; receipt.street = transaction.organisation.streetName; receipt.postcode = transaction.organisation.postcode; receipt.town = transaction.organisation.town; receipt.recurring = transaction.recurring; if (transaction.recurring == "None") { receipt.recurring = ""; } receipt.category = transaction.category; if (transaction.category == "Uncategorised") { receipt.category = ""; } receipt.amount = transaction.amount.text.toString(); receipt.time = DateFormat("yyyy-MM-dd'T'hh:mm':00.000+01:00'") .format(transaction.date) .toString(); receipt.essential = transaction.isEssential.toString(); submitReceiptAPI(context, receipt); } List _recurringOptions = new List(7); List _categories = new List(); @override void initState() { super.initState(); } @override Widget build(BuildContext context) { var _widgetHeight = MediaQuery.of(context).size.height * 0.06 < 40.0 ? 40.0 : MediaQuery.of(context).size.height * 0.06; var _fontSize = _widgetHeight * 0.45; var _fontSizeButton = _widgetHeight * 0.5; if (_categories.isEmpty) { Future> _futureCats = getCats(); _categories.add("Fetching categories..."); _futureCats.then((value) { _categories = value; _categories.insert(0, "Uncategorised"); setState(() {}); }); } _recurringOptions[0] = "None"; _recurringOptions[1] = "Daily"; _recurringOptions[2] = "Weekly"; _recurringOptions[3] = "Fortnightly"; _recurringOptions[4] = "Monthly"; _recurringOptions[5] = "Quarterly"; _recurringOptions[6] = "Yearly"; // these will be difficult to fetch from server as they are coded into the site's HTML rather than fetched return PlatformScaffold( appBar: AppBar( backgroundColor: Colors.blue[400], title: Text( "Submit Receipt", style: TextStyle( fontSize: 20, color: Colors.white, ), ), centerTitle: true, iconTheme: IconThemeData(color: Colors.black), ), body: ListView( children: [ // each CHILD has its own horizontal padding because if the listView // has padding, Android's end-of-scroll animation // doesn't fit the screen properly and looks weird Container( padding: EdgeInsets.fromLTRB( MediaQuery.of(context).size.width * 0.025, MediaQuery.of(context).size.height * 0.025, 0, 0.0), child: Text( "Receipt Details", style: TextStyle( fontSize: 26, color: Colors.grey[700], fontWeight: FontWeight.bold, ), ), ), // "Receipt Details" title Container( padding: EdgeInsets.fromLTRB( MediaQuery.of(context).size.width * 0.05, 15, MediaQuery.of(context).size.width * 0.05, 0.0), child: Tooltip( message: "Date and time of transaction", child: Row( children: [ Container( child: Text( "Date/Time", style: TextStyle( fontSize: _fontSize, color: Colors.black, fontWeight: FontWeight.bold, ), ), width: MediaQuery.of(context).size.width * 0.3, ), Container( padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), height: _widgetHeight, width: MediaQuery.of(context).size.width * 0.6, child: RaisedButton( onPressed: () { showModalBottomSheet( context: context, builder: (BuildContext builder) { return Container( height: MediaQuery.of(context) .copyWith() .size .height / 3, child: CupertinoDatePicker( initialDateTime: transaction.date.isAfter(DateTime.now()) ? DateTime.now() : transaction.date, onDateTimeChanged: (DateTime newDate) { setState(() => { newDate.isAfter(DateTime.now()) ? transaction.date = DateTime.now() : transaction.date = newDate, }); }, use24hFormat: true, maximumDate: DateTime.now(), ), ); }); }, child: Text( transaction.date == null ? 'None set.' : transaction.date.year != DateTime.now().year ? '${new DateFormat.MMMd().format(transaction.date)}' + " " + transaction.date.year.toString() + " at " + '${new DateFormat.Hm().format(transaction.date)}' : transaction.date.day == DateTime.now().day && transaction.date.month == DateTime.now().month ? "Today at " + '${new DateFormat.Hm().format(transaction.date)}' : '${new DateFormat.MMMd().format(transaction.date)}' + " at " + '${new DateFormat.Hm().format(transaction.date)}', style: TextStyle( color: Colors.white, fontSize: _fontSizeButton), ), color: Colors.blue, ), ), ], ), ), ), // Date/Time picker Container( padding: EdgeInsets.fromLTRB( MediaQuery.of(context).size.width * 0.05, 15, MediaQuery.of(context).size.width * 0.05, 0.0), child: Tooltip( message: "Transaction payee", child: Row( children: [ Container( child: Text( "Payee", style: TextStyle( fontSize: _fontSize, color: Colors.black, fontWeight: FontWeight.bold, ), ), width: MediaQuery.of(context).size.width * 0.3, ), Container( padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), height: _widgetHeight, width: MediaQuery.of(context).size.width * 0.6, child: RaisedButton( onPressed: () { var organisations = new FindOrganisations(); var orgDialog = organisations.dialog(context); orgDialog.then((organisation) { try { organisation.name.length; transaction.organisation = organisation; // debugPrint(organisation.name); setState(() {}); } catch (_) { debugPrint("No organisation chosen."); } }); }, child: Text( transaction.organisation.name == null ? 'Find' : transaction.organisation.name.length > 14 ? transaction.organisation.name .substring(0, 12) + "..." : transaction.organisation.name, style: TextStyle( color: Colors.white, fontSize: _fontSizeButton), ), color: Colors.blue, ), ), ], ), ), ), // Organisation picker Container( padding: EdgeInsets.fromLTRB( MediaQuery.of(context).size.width * 0.05, 15, MediaQuery.of(context).size.width * 0.05, 0.0), child: Tooltip( message: "Repeating?", child: Row( children: [ Container( child: Text( "Recurring", style: TextStyle( fontSize: _fontSize, color: Colors.black, fontWeight: FontWeight.bold, ), ), width: MediaQuery.of(context).size.width * 0.3, ), Container( padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), height: _widgetHeight, width: MediaQuery.of(context).size.width * 0.6, child: RaisedButton( onPressed: () { transaction.recurring = _recurringOptions[0]; setState(() {}); showModalBottomSheet( context: context, builder: (BuildContext builder) { return Container( height: MediaQuery.of(context) .copyWith() .size .height / 3, child: CupertinoPicker( backgroundColor: Colors.white, children: _recurringOptions .map((thisOption) => Text(thisOption, style: TextStyle(fontSize: 30))) .toList(), onSelectedItemChanged: ((newValue) { transaction.recurring = _recurringOptions[newValue]; setState(() {}); }), magnification: 1.1, useMagnifier: true, itemExtent: 36, ), ); }); }, child: Text( transaction.recurring == null ? 'None' : transaction.recurring, style: TextStyle( color: Colors.white, fontSize: _fontSizeButton), ), color: Colors.blue, ), ), ], ), ), ), // Recurring picker Container( padding: EdgeInsets.fromLTRB( MediaQuery.of(context).size.width * 0.05, 15, MediaQuery.of(context).size.width * 0.05, 0.0), child: Row( children: [ Container( child: Text( "Category", style: TextStyle( fontSize: _fontSize, color: Colors.black, fontWeight: FontWeight.bold, ), ), width: MediaQuery.of(context).size.width * 0.3, ), Container( padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), height: _widgetHeight, width: MediaQuery.of(context).size.width * 0.6, child: Tooltip( message: "Category of transaction", child: RaisedButton( onPressed: () { transaction.category = _categories[0]; setState(() {}); showModalBottomSheet( context: context, builder: (BuildContext builder) { return Container( height: MediaQuery.of(context) .copyWith() .size .height / 3, child: CupertinoPicker( backgroundColor: Colors.white, children: _categories .map((thisOption) => Text( thisOption, style: TextStyle(fontSize: 30), )) .toList(), onSelectedItemChanged: ((newValue) { transaction.category = _categories[newValue]; setState(() {}); }), magnification: 1.1, useMagnifier: true, itemExtent: 36, ), ); }); }, child: Text( transaction.category == null ? 'None' : transaction.category, style: TextStyle( color: Colors.white, fontSize: _fontSizeButton), ), color: Colors.blue, ), ), ), ], ), ), // Category picker Container( padding: EdgeInsets.fromLTRB( MediaQuery.of(context).size.width * 0.05, 15, MediaQuery.of(context).size.width * 0.05, 0.0), child: Tooltip( message: "Essential or not", child: Row( children: [ Container( child: Text( "Essential", style: TextStyle( fontSize: _fontSize, color: Colors.black, fontWeight: FontWeight.bold, ), ), width: MediaQuery.of(context).size.width * 0.3, ), Container( height: _widgetHeight, width: MediaQuery.of(context).size.width * 0.6, child: Checkbox( value: transaction.isEssential, onChanged: ((value) { setState(() => transaction.isEssential = value); }), ), ), ], ), ), ), // Essential Container( padding: EdgeInsets.fromLTRB( MediaQuery.of(context).size.width * 0.05, 15, MediaQuery.of(context).size.width * 0.05, 0.0), child: Tooltip( message: "Transaction amount", child: Row( children: [ Container( child: Text( "Amount", style: TextStyle( fontSize: _fontSize, color: Colors.black, fontWeight: FontWeight.bold, ), ), width: MediaQuery.of(context).size.width * 0.3, ), Container( padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), height: _widgetHeight, width: MediaQuery.of(context).size.width * 0.6, child: TextField( style: TextStyle( fontSize: _fontSize, ), textAlign: TextAlign.center, controller: transaction.amount, decoration: InputDecoration(hintText: "0.00"), keyboardType: TextInputType.numberWithOptions( decimal: true, signed: true), ), ), ], ), ), ), // Amount picker Padding( padding: EdgeInsets.fromLTRB( MediaQuery.of(context).size.width * 0.05, MediaQuery.of(context).size.height * 0.03, MediaQuery.of(context).size.width * 0.05, 15.0), child: Tooltip( message: "Submit receipt", child: Container( height: _widgetHeight * 1.7, child: ClipRRect( borderRadius: BorderRadius.circular(2), child: Opacity( opacity: 1, child: Stack( children: [ AnimatedBackground( [Colors.blue, Colors.lightBlue[300]], Colors.lightBlue, Alignment.topLeft, Alignment.bottomRight, 4), Material( type: MaterialType.transparency, child: InkWell( child: Center( child: Text( "GO", style: TextStyle( color: Colors.white, fontSize: 30.0), ), ), onTap: () { try { if (transaction.amount.text == "" || transaction.organisation.name == null) { showDialog( context: context, builder: (BuildContext context) { return _invalidDialog(context); }); } else { if (double.tryParse( transaction.amount.text) != null && double.tryParse(transaction.amount.text) > 0) { _submitReceipt(transaction); } else { showDialog( context: context, builder: (BuildContext context) { return _invalidDialog(context); }); } } } catch (_) { showDialog( context: context, builder: (BuildContext context) { return _invalidDialog(context); }); } }, ), ), ], ), ), ), ), ), ), ], ), ); } }