diff --git a/lib/main.dart b/lib/main.dart index 7afd692..73d53e2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -41,6 +41,10 @@ class HomePage extends StatefulWidget { class _HomePageState extends State { var pageSelected = 0; + refresh() { + setState(() {}); + } + @override Widget build(BuildContext context) { Widget page; @@ -48,7 +52,9 @@ class _HomePageState extends State { switch (pageSelected) { case 0: page = ExpensePage(); - dialog = ExpenseInputDialog(); + dialog = ExpenseInputDialog( + notifyParent: refresh, + ); case 1: page = IncomePage(); case 2: @@ -79,49 +85,44 @@ class _HomePageState extends State { return LayoutBuilder(builder: (context, constraints) { return Scaffold( - // TODO: Add a drawer instead of nav rail. - body: Row( - children: [ - SafeArea( - child: NavigationRail( - extended: constraints.maxWidth >= 800, - destinations: [ - NavigationRailDestination( - icon: Icon(Icons.payment), - label: Text('Expenses'), - ), - NavigationRailDestination( - icon: Icon(Icons.account_balance), - label: Text('Income'), - ), - NavigationRailDestination( - icon: Icon(Icons.attach_money), - label: Text('Liquid Assets'), - ), - NavigationRailDestination( - icon: Icon(Icons.bar_chart), - label: Text('Projections'), - ), - NavigationRailDestination( - icon: Icon(Icons.settings), - label: Text('Settings'), - ), - ], - selectedIndex: pageSelected, - onDestinationSelected: (value) { - setState(() { - pageSelected = value; - }); - }, - ), + appBar: AppBar(title: Text("Expense Tracker")), + drawer: NavigationRail( + extended: constraints.maxWidth >= 800, + destinations: [ + NavigationRailDestination( + icon: Icon(Icons.payment), + label: Text('Expenses'), ), - Expanded( - child: Container( - color: Theme.of(context).colorScheme.primaryContainer, - child: page, - ), + NavigationRailDestination( + icon: Icon(Icons.account_balance), + label: Text('Income'), + ), + NavigationRailDestination( + icon: Icon(Icons.attach_money), + label: Text('Liquid Assets'), + ), + NavigationRailDestination( + icon: Icon(Icons.bar_chart), + label: Text('Reports'), + ), + NavigationRailDestination( + icon: Icon(Icons.settings), + label: Text('Settings'), ), ], + selectedIndex: pageSelected, + onDestinationSelected: (value) { + setState(() { + pageSelected = value; + Navigator.pop(context); + }); + }, + ), + body: Center( + child: Container( + color: Theme.of(context).colorScheme.primaryContainer, + child: page, + ), ), floatingActionButton: floatingButton, ); diff --git a/lib/pages/expense.dart b/lib/pages/expense.dart index d9a68af..3da7eb0 100644 --- a/lib/pages/expense.dart +++ b/lib/pages/expense.dart @@ -13,47 +13,36 @@ class ExpensePage extends StatelessWidget { @override Widget build(BuildContext context) { return ListView.builder( - itemCount: expenses.length, - itemBuilder: (_, index) { - final Expense curr = expenses[index]; - return Center( - child: Padding( - padding: const EdgeInsets.all(4.0), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: Colors.greenAccent, - ), - child: Column( - children: [ - Text(curr.name), - Text("${curr.cost.toString()} ${curr.frequency.title}"), - ], - ), + itemCount: expenses.length, + itemBuilder: (_, index) { + final Expense curr = expenses[index]; + return Center( + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: Colors.greenAccent, + ), + child: Column( + children: [ + Text(curr.name), + Text("${curr.cost.toString()} ${curr.frequency.title}"), + ], ), ), - ); - }); - /* - return ListView( - children: [ - ListTile( - title: Text("Fake Item 1"), - subtitle: Text("30.00 / month"), - ), - ListTile( - title: Text("Fake Item 2"), - subtitle: Text("180.00 / year"), - ), - ], + ), + ); + }, ); - */ } } class ExpenseInputDialog extends StatefulWidget { + final Function() notifyParent; const ExpenseInputDialog({ super.key, + required this.notifyParent, }); @override @@ -70,9 +59,6 @@ class _ExpenseInputDialogState extends State { @override Widget build(BuildContext context) { - const inputWidth = 300.0; - const inputHeight = 50.0; - List freqValues = []; for (var freq in Frequency.values) { freqValues.add(DropdownMenuItem(value: freq, child: Text(freq.title))); @@ -83,130 +69,112 @@ class _ExpenseInputDialogState extends State { title: Center(child: Text("Add New Expense")), content: Form( key: _expenseFormKey, - autovalidateMode: AutovalidateMode.onUserInteraction, + //autovalidateMode: AutovalidateMode.onUserInteraction, child: Column(mainAxisSize: MainAxisSize.min, spacing: 10, children: [ - SizedBox( - width: inputWidth, - height: inputHeight, - child: TextFormField( - keyboardType: TextInputType.text, - decoration: InputDecoration( - labelText: "Name", - hintText: "Example: Red Pocket Phone Bill", - ), - validator: (value) { - if (value!.isEmpty) { - return "Name must be provided."; - } - return null; - }, - onSaved: (newValue) { - _name = newValue!; - }, + TextFormField( + keyboardType: TextInputType.text, + decoration: InputDecoration( + labelText: "Name", + hintText: "Example: Red Pocket Phone Bill", ), + validator: (value) { + if (value!.isEmpty) { + return "Name must be provided."; + } + return null; + }, + onSaved: (newValue) { + _name = newValue!; + }, ), - SizedBox( - width: inputWidth, - height: inputHeight, - child: TextFormField( - keyboardType: TextInputType.numberWithOptions(decimal: true), - decoration: InputDecoration( - labelText: "Cost", hintText: "Example: 10.00"), - validator: (value) { - if (value!.isEmpty) { - return "Cost must be provided."; - } - if (double.tryParse(value) == null) { - return "Cost must be a valid number."; - } - return null; - }, - onSaved: (newValue) { - _cost = double.parse(newValue!); - }, - ), + TextFormField( + keyboardType: TextInputType.numberWithOptions(decimal: true), + decoration: + InputDecoration(labelText: "Cost", hintText: "Example: 10.00"), + validator: (value) { + if (value!.isEmpty) { + return "Cost must be provided."; + } + if (double.tryParse(value) == null) { + return "Cost must be a valid number."; + } + return null; + }, + onSaved: (newValue) { + _cost = double.parse(newValue!); + }, ), - SizedBox( - width: inputWidth, - height: inputHeight, - child: DropdownButtonFormField( - items: freqValues, - decoration: InputDecoration( - labelText: "Recurrence", hintText: "Example: Monthly"), - validator: (value) { - if (value == null) { - return "Frequency must be provided."; - } - if (!Frequency.values.contains(value)) { - return "Value not valid."; - } - return null; - }, - onChanged: (newValue) { - _freq = newValue; - }, - ), + DropdownButtonFormField( + items: freqValues, + decoration: InputDecoration( + labelText: "Recurrence", hintText: "Example: Monthly"), + validator: (value) { + if (value == null) { + return "Frequency must be provided."; + } + if (!Frequency.values.contains(value)) { + return "Value not valid."; + } + return null; + }, + onChanged: (newValue) { + _freq = newValue; + }, ), - SizedBox( - width: inputWidth, - height: inputHeight, - child: TextFormField( - keyboardType: TextInputType.text, - decoration: InputDecoration( - labelText: "Description", - hintText: "Example: 1GB data with unlimited talk & text."), - validator: (value) { - return null; - }, - onSaved: (newValue) { - _desc = newValue!; - }, - ), + TextFormField( + keyboardType: TextInputType.text, + decoration: InputDecoration( + labelText: "Description", + hintText: "Example: 1GB data with unlimited talk & text."), + validator: (value) { + return null; + }, + onSaved: (newValue) { + _desc = newValue!; + }, ), ]), ), actions: [ - SizedBox( - width: inputWidth, - height: inputHeight, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - ElevatedButton.icon( - onPressed: () { - print("TODO: Clear fields!"); - Navigator.of(context).pop(); - }, - icon: Icon(Icons.cancel), - label: Text('Cancel'), - ), - ElevatedButton.icon( - onPressed: () { - print("TODO: Save expense!"); - if (_expenseFormKey.currentState!.validate()) { - _expenseFormKey.currentState!.save(); - setState(() { - expenses.add( - Expense( - name: _name, - cost: _cost, - frequency: _freq, - description: _desc), - ); - }); - print(expenses.toString()); - for (var expense in expenses) { - print(expense.toString()); - } - Navigator.of(context).pop(); + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ElevatedButton.icon( + onPressed: () { + print("TODO: Clear fields!"); + Navigator.of(context).pop(); + }, + icon: Icon(Icons.cancel), + label: Text('Cancel'), + ), + ElevatedButton.icon( + onPressed: () { + print("TODO: Save expense!"); + if (_expenseFormKey.currentState!.validate()) { + _expenseFormKey.currentState!.save(); + setState(() { + expenses.add( + Expense( + name: _name, + cost: _cost, + frequency: _freq, + description: _desc), + ); + }); + widget.notifyParent(); + + print(expenses.toString()); + for (var expense in expenses) { + print(expense.toString()); } - }, - icon: Icon(Icons.save), - label: Text('Submit'), - ), - ], - ), + Navigator.of(context).pop(); + } + }, + icon: Icon(Icons.save), + label: Text('Submit'), + ), + ], ) ], );