Beginning FlutterFire

Aug 30 2022 · Dart 2.16, Flutter 3.0, Visual Studio Code 1.69

Part 3: Read & Write Data with the Cloud Firestore

13. Create the Activity Detail Screen

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 12. Create the Activities Screen Next episode: 14. Add & Update Data into the Firestore Database

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 13. Create the Activity Detail Screen

Now you will create the screen that allows users to insert a new activity and update an existing one.

In the screens folder of the project, create a new file: call this “activity_detail_screen.dart”. At the top of the file, as usual, import material.dart.

Under that, also import our activity.dart file in the data folder, and of course also firebase_helper.dart, also in the data folder. Next, create a stateful widget, using the stful shortcut. Let’s call this “ActivityDetailScreen”.

This widget takes an Activity object when it’s called: this is the Activity that users will insert or update when they get to this screen from the activities screen. So, let’s add a final Activity, called activity, and set it in the ActivityScreen constructor:

ActivityScreen(this.activity, {Key? key}) : super(key: key); 
  final Activity activity; 

At the top of the State class, we will create four TextEditingController widgets, that will deal with the textFields that contain the activity properties.

So, add a final TextEditingController, called txtDescription that’s an instance of TextEditingController. Let’s repeat the same for txtDay, txtBeginTime, and txtEndTime. Let’s also create an instance of our FirebaseHelper class:

final TextEditingController txtDescription = TextEditingController(); 
final TextEditingController txtDay = TextEditingController(); 
final TextEditingController txtBeginTime = TextEditingController(); 
final TextEditingController txtEndTime = TextEditingController(); 
final helper = FirebaseHelper(); 

This screen will contain four TextFields: each one will have a TextEditingController, and some styling, including a border, a hint text, and a label text. In other words, all these widgets will be very similar one to the other. So, instead of repeating the same code for each of them, we’ll create a configurable widget for those.

At the bottom of the activity_detail_screen.dart file, create a stateless widget, and call it ActivityTextField.

This will have two fields: a final String, called label, and a final TextEditingController, called controller. Add these to the widget constructor: so, this.label and this.controller. In the build method, let’s return a Padding.

For the padding, let’s set an EdgeInsets.all of 16 device independent pixels.The child is a TextField, whose controller is the controller that was passed to the widget constructor. Now set the decoration, that takes an InputDecoration.

First let’s set a border: here will add a const OutputInputBorder. Let’s also add a hintText, that takes the label String passed in the constructor, and a labelText, which also takes the label string.

class ActivityTextField extends StatelessWidget { 
  const ActivityTextField(this.label, this.controller, {Key? key}) 
      : super(key: key); 
  final String label; 
  final TextEditingController controller; 

  @override 
  Widget build(BuildContext context) { 
    return Padding( 
      padding: const EdgeInsets.all(16.0), 
      child: TextField( 
        controller: controller, 
        decoration: InputDecoration( 
            border: const OutlineInputBorder(), 
            hintText: label, 
            labelText: label), 
      ), 
    ); 
  } 
} 

Now we can get back to the screen widget.
At the top of the class, let’s declare a List of ActivityTextField widgets, that we can call controls. It will be emtpy at first.

List<ActivityTextField> controls = []; 

Now, override the initState method. Here let’s set the controls list, so that it contains an ActivityTextField for each property of the activity we want to show to our users:

The first one will be an instance of ActivityTextField with “Description” as label, and txtDescription as controller. Let’s repeat the same three more times: the second ActivityTextField will have “Date” as label and txtDat as controller. The third “Begin” as label and txtBeginTime as controller, and the last “End” as label and txtEndTime as controller.

controls = [ 
      ActivityTextField('Description', txtDescription), 
      ActivityTextField('Date', txtDay), 
      ActivityTextField('Begin', txtBeginTime), 
      ActivityTextField('End', txtEndTime), 
    ]; 

Still in the initState method, let’s read the properties of the activity that’s been passed to the screen, and update the controllers accordingly. This will be useful especially when the activity will be updated, because for a new activity the fields will just contain an empty string. So, let’s set txtDescription.text: this takes the widget activity, at the description field.

Let’s repeat for txtDay, that tales the day field, txtBeginTime, that takes the beginTime field, and txtEndTime, that takes endTime.

txtDescription.text = widget.activity.description; 
txtDay.text = widget.activity.day; 
txtBeginTime.text = widget.activity.beginTime; 
txtEndTime.text = widget.activity.endTime; 

We are finally ready to complete the build method. Let’s return a Scaffold with an appbar, that contains an Appbar widget, whose title is a const Text, with “Activity”.

In the body of the Scaffold, return a ListView builder. Its itemCount takes the length of the controls list. Its itembuilder takes the current context and the position of each item in the list: here retunr a Card, whose child takes the widget at the current position: what happens here is that the listView will contain our 4 widgets, each containing the textField that allows our users to read and write data to the Firestore database.

ListView.builder( 
  itemCount: controls.length, 
  itemBuilder: (context, position) { 
    return Card( 
      child: controls[position], 
    ); 
  }), 

To complete the UI for this screen, add a floatingActionButton. We’ll use this to save the current activity in the Firestore database. The child of the floatingActionButton is an Icon, containing the save icon from the material icons set. Let’s also add the onPressed property, that takes an empty method right now.

OK, the UI for this screen is ready. Let’s add the code to insert and update an activity into the Firestore database next.