• Skip to main content
  • Skip to primary sidebar

Ravi Shankar

Tweaking Apps

  • About
  • Portfolio
  • Privacy Policy
You are here: Home / Flutter / Easy Split – Adding Expense page – Flutter – Day 6

Easy Split – Adding Expense page – Flutter – Day 6

April 2, 2021 By Ravi Shankar

Today we are going to add new expense screen for adding expenses

  1. Add screen navigation from expense list screen.
  2. Add a model class for expense
  3. Expense screen design and passing expense data back to parent screen.

Add Expense Page

Let us create a dummy expense page with title and button to save the details.

import 'package:flutter/cupertino.dart';

class ExpensePage extends StatefulWidget {
  final String userName;

  ExpensePage(this.userName);

  @override
  _MyListState createState() => _MyListState();
}

class _MyListState extends State<ExpensePage> {
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text('Add Expense'),
        trailing: CupertinoButton(
          padding: EdgeInsets.zero,
          child: Icon(
            CupertinoIcons.floppy_disk,
            size: 35,
          ),
          onPressed: () {},
        ),
      ),
      child: Text('Expenses'),
    );
  }
}

Now we need to add the code for calling Expense page on tap of the + button in ExpenseList page.

Navigator.push(
                            context,
                            MaterialPageRoute(
                              builder: (context) => ExpensePage(userName),
                            ));
                      },

We are passing username as an argument in the constructor, this is to link user with the expense. Later this will be changed to user object instead of user name.

Expense model class

Here is code snippet of Expense model class which will act as the placeholder for Expense.

class Expense {
  String name;
  DateTime dateTime;
  double amount;
  String details;
}

Expense Screen design

Let us modify the expense page and add name, date, amount and detail field. I will be using a static ListView to arrange all these fields. For date field will be using CupertinoDateField. Here is the expensePage.dart page.

import 'package:easysplit/model/expense.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';

class ExpensePage extends StatefulWidget {
  final String userName;

  ExpensePage(this.userName);

  @override
  _MyListState createState() => _MyListState();
}

class _MyListState extends State<ExpensePage> {
  TextEditingController nameController;
  DateTime _dateTime;
  TextEditingController dateController;
  TextEditingController amountController;
  TextEditingController detailController;

  Expense expense = Expense();

  @override
  void initState() {
    super.initState();
    nameController = TextEditingController(text: '');
    dateController = TextEditingController(text: formatDate(DateTime.now()));
    amountController = TextEditingController(text: '');
    detailController = TextEditingController(text: '');
  }

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: Text('Add Expense'),
          trailing: CupertinoButton(
            padding: EdgeInsets.zero,
            child: Icon(
              CupertinoIcons.floppy_disk,
              size: 35,
            ),
            onPressed: () {
              expense.name = nameController.text;
              expense.dateTime = _dateTime;
              if (amountController.text != '') {
                expense.amount = double.parse(amountController.text);
              }
              expense.details = detailController.text;
              Navigator.pop(context, expense);
            },
          ),
        ),
        child: _myListView(context));
  }

  Widget _myListView(BuildContext context) {
    return Scaffold(
      body: ListView(
        children: <Widget>[
          ListTile(
            title: Text('Name:'),
          ),
          ListTile(
            title: CupertinoTextField(
              controller: nameController,
            ),
          ),
          ListTile(
            title: Text('Date:'),
          ),
          ListTile(
              title: CupertinoTextField(
            controller: dateController,
            readOnly: true,
            onTap: () => _showDatePicker(context),
          )),
          ListTile(
            title: Text('Amount:'),
          ),
          ListTile(
            title: CupertinoTextField(
              controller: amountController,
              keyboardType: TextInputType.number,
              inputFormatters: <TextInputFormatter>[
                FilteringTextInputFormatter.digitsOnly
              ], // Only numbers can be entered
            ),
          ),
          ListTile(
            title: Text('Detail:'),
          ),
          ListTile(
            title: CupertinoTextField(
              controller: detailController,
              maxLines: 3,
            ),
          ),
        ],
      ),
    );
  }

  void _showDatePicker(ctx) {
    // showCupertinoModalPopup is a built-in function of the cupertino library
    showCupertinoModalPopup(
        context: ctx,
        builder: (_) => Container(
              height: 500,
              color: Color.fromARGB(255, 255, 255, 255),
              child: Column(
                children: [
                  Container(
                    height: 400,
                    child: CupertinoDatePicker(
                        initialDateTime: DateTime.now(),
                        onDateTimeChanged: (val) {
                          setState(() {
                            _dateTime = val;
                            if (_dateTime != null) {
                              dateController.text = formatDate(_dateTime);
                            }
                          });
                        }),
                  ),

                  // Close the modal
                  CupertinoButton(
                    child: Text('OK'),
                    onPressed: () => Navigator.of(ctx).pop(),
                  )
                ],
              ),
            ));
  }

  String formatDate(DateTime dateTime) {
    DateFormat dateFormat = DateFormat('dd MMM hh:mm');
    return dateFormat.format(dateTime);
  }
}

Pass custom object back to parent screen

In order to pass the expense object back to expense list page, pass the expense object as part of the Navigator pop code.

 Navigator.pop(context, expense);

In the parent page (expense list), add a new function which does the navigation to expense page. This function will be called in onTap of the + button. This function will be added with async attribute for retrieving the expense object when returned from expense page.

void moveToExpensePage(String item) async {
    final Expense expense = await Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => ExpensePage(userName),
        ));
    print(expense.amount);
  }

References

  1. Static ListView
  2. Cupertino DatePicker
  3. Navigator Pop – Pass data

Filed Under: Flutter

Primary Sidebar

TwitterLinkedin

Recent Posts

  • Easy Split – Link Expense and User object – Flutter – Day 7
  • Easy Split – Adding Expense page – Flutter – Day 6
  • Easy Split – Showing multiple views – Flutter – Day 5
  • Easy Split – Add screen navigation – Flutter – Day 4
  • Easy Split – Add alert dialog – Flutter – Day 3

Copyright 2021 © rshankar.com