#100DaysOfCodeChallenge -Crop Management Information System- Day 3
Tags: 100daysofcode, flutter, dart
Published: 2021-06-26 23:29:49

##Recap

On [Day 2](https://dev.to/curtlycritchlow/100daysofcodechallenge-crop-management-information-system-day-2-3fif) I created the `FarmerServce()` class that is responsible for making network calls to Firebase Auth Farmer collection and documents. I also created the `AddFarmerCommand()` class that is responsible for passing an instance of the `FarmerServiceModel()` to `FarmerService()`.

## Overview

Today I created the Farmer registration form. This form will accept user input than will create an instance of the `FarmerServiceModel()` that will be stored in [cloud firestore](https://firebase.flutter.dev/docs/firestore/overview).

Building this form exposed weaknesses in my understanding for Flutter layout and using dart late variable.

## Add Farmer Form

Below is a screenshot of the form design followed by the code.
![Farmer Form](https://drive.google.com/uc?id=1QTZIm4P0kkFn3I5aRUXX7NTbdZaYmoBR)



NB: 436 lines of code
```Dart
class AddFarmerPage extends StatefulWidget {
  static String routeName = 'AddFarmerPage';
  const AddFarmerPage({
    Key? key,
  }) : super(key: key);

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

class _AddFarmerPageController extends State<AddFarmerPage> {
  @override
  Widget build(BuildContext context) => _AddFarmerPageView(this);
  FarmerServiceModel farmer = FarmerServiceModel.form();
  final GlobalKey<FormState> _formkey = GlobalKey<FormState>();
  bool _formChanged = false;

  late FocusNode registrationNumberFocusNode;
  late FocusNode nationalIdFocusNode;
  late FocusNode profilePictureFocusNode;
  late FocusNode firstNameFocusNode;
  late FocusNode lastNameFocusNode;
  late FocusNode nicknameFocusNode;
  late FocusNode dateOfBirthFocusNode;
  late FocusNode genderFocusNode;
  late FocusNode ethnicityFocusNode;
  late FocusNode maritalStatusFocusNode;
  late FocusNode addressFocusNode;
  late FocusNode isHeadOfHouseholdFocusNode;
  late FocusNode isFarmingPrimaryIncomeSourceFocusNode;
  late FocusNode isActiveFarmerFocusNode;
  late FocusNode farmerCategoryFocusNode;
  late FocusNode subsectorFocusNode;
  late FocusNode operationScaleFocusNode;

  @override
  void initState() {
    super.initState();
    registrationNumberFocusNode = FocusNode();
    nationalIdFocusNode = FocusNode();
    profilePictureFocusNode = FocusNode();
    firstNameFocusNode = FocusNode();
    lastNameFocusNode = FocusNode();
    nicknameFocusNode = FocusNode();
    dateOfBirthFocusNode = FocusNode();
    genderFocusNode = FocusNode();
    ethnicityFocusNode = FocusNode();
    maritalStatusFocusNode = FocusNode();
    addressFocusNode = FocusNode();
    isHeadOfHouseholdFocusNode = FocusNode();
    isFarmingPrimaryIncomeSourceFocusNode = FocusNode();
    isActiveFarmerFocusNode = FocusNode();
    farmerCategoryFocusNode = FocusNode();
    subsectorFocusNode = FocusNode();
    operationScaleFocusNode = FocusNode();
  }

  @override
  void dispose() {
    super.dispose();
    registrationNumberFocusNode.dispose();
    nationalIdFocusNode.dispose();
    profilePictureFocusNode.dispose();
    firstNameFocusNode.dispose();
    lastNameFocusNode.dispose();
    nicknameFocusNode.dispose();
    dateOfBirthFocusNode.dispose();
    genderFocusNode.dispose();
    ethnicityFocusNode.dispose();
    maritalStatusFocusNode.dispose();
    addressFocusNode.dispose();
    isHeadOfHouseholdFocusNode.dispose();
    isFarmingPrimaryIncomeSourceFocusNode.dispose();
    isActiveFarmerFocusNode.dispose();
    farmerCategoryFocusNode.dispose();
    subsectorFocusNode.dispose();
    operationScaleFocusNode.dispose();
  }

  //FORM LEVEL METHODS
  void _hanldeOnFormChanged() {
    if (_formChanged) return;
    setState(() {
      _formChanged = true;
    });
  }

  void _handleRegisterFarmer() async {
    if (_formkey.currentState!.validate()) {
      _formkey.currentState!.save();
      // todo: create register farmer command
    }
  }

  void _handleDropdownOnChanged(String? value) {}

  String _date = '';

  void _showDatePicker() {
    showDatePicker(
      context: context,
      initialDate: DateTime.now(),
      firstDate: DateTime(1900),
      lastDate: DateTime.now(),
    ).then((value) {
      if (value != null) {
        setState(() {
          // farmer.saveDateOfBirth(value);
          // print(farmer.dateOfBirth);
          print(value.toString());
          _date = value.toString();
          // print(_date);
        });
      }
    });
  }
}

class _AddFarmerPageView
    extends WidgetView<AddFarmerPage, _AddFarmerPageController> {
  final state;
  const _AddFarmerPageView(this.state) : super(state);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Add Farmer'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(24.0),
        child: Form(
            key: state._formkey,
            onChanged: state._hanldeOnFormChanged,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                Padding(
                  padding: const EdgeInsets.only(bottom: 24.0),
                  child: Center(
                    child: Text(
                      'Farmer Registration Form',
                      style: TextStyles.title.bold,
                    ),
                  ),
                ),
                Expanded(
                  child: ListView(children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: [
                        // Registration Number
                        Expanded(
                          child: TextFormField(
                            decoration: FormStyles.textFieldDecoration(
                                labelText: 'Registration Number'),
                            focusNode: state.registrationNumberFocusNode,
                            textInputAction: TextInputAction.next,
                            keyboardType: TextInputType.visiblePassword,
                            autovalidateMode:
                                AutovalidateMode.onUserInteraction,
                            validator: state.farmer.validateRegistrationNumber,
                            onSaved: state.farmer.saveRegistrationNumber,
                          ),
                        ),
                        SizedBox(
                          width: 20.0,
                        ),
                        // National ID Number
                        Expanded(
                          child: TextFormField(
                            decoration: FormStyles.textFieldDecoration(
                                labelText: 'National ID Number'),
                            focusNode: state.nationalIdFocusNode,
                            textInputAction: TextInputAction.next,
                            autovalidateMode:
                                AutovalidateMode.onUserInteraction,
                            validator: state.farmer.validateNationalId,
                            onSaved: state.farmer.saveNationalId,
                          ),
                        )
                      ],
                    ),
                    Row(
                      children: [
                        Expanded(
                          child: Column(
                            // mainAxisSize: MainAxisSize.min,
                            crossAxisAlignment: CrossAxisAlignment.stretch,
                            children: [
                              SizedBox(
                                height: 300,
                                width: 300,
                                child: Container(
                                  color: Colors.blue,
                                ),
                              ),
                              ElevatedButton.icon(
                                  onPressed: () {},
                                  icon: Icon(Icons.camera_alt_outlined),
                                  label: Text('Take Picture')),
                            ],
                          ),
                        ),
                        SizedBox(width: 30.0),
                        Expanded(
                          child: Column(children: [
                            // FIRST NAME
                            TextFormField(
                              decoration: FormStyles.textFieldDecoration(
                                  labelText: 'First Name'),
                              focusNode: state.firstNameFocusNode,
                              textInputAction: TextInputAction.next,
                              autovalidateMode:
                                  AutovalidateMode.onUserInteraction,
                              validator: state.farmer.validateFirstName,
                              onSaved: state.farmer.saveFirstName,
                            ),

                            // NICKNAME
                            TextFormField(
                              decoration: FormStyles.textFieldDecoration(
                                  labelText: 'Nickname'),
                              focusNode: state.nicknameFocusNode,
                              textInputAction: TextInputAction.next,
                              autovalidateMode:
                                  AutovalidateMode.onUserInteraction,
                              validator: state.farmer.validateNickname,
                              onSaved: state.farmer.saveNickname,
                            ),
                            // LAST NAME
                            TextFormField(
                              decoration: FormStyles.textFieldDecoration(
                                  labelText: 'Last Name'),
                              focusNode: state.lastNameFocusNode,
                              textInputAction: TextInputAction.next,
                              autovalidateMode:
                                  AutovalidateMode.onUserInteraction,
                              validator: state.farmer.validateLastName,
                              onSaved: state.farmer.saveLastName,
                            ),
                          ]),
                        )
                      ],
                    ),
                    SizedBox(
                      height: 15,
                    ),
                    Row(
                      children: [
                        Expanded(
                          child: TextFormField(
                            readOnly: true,
                            focusNode: state.dateOfBirthFocusNode,
                            decoration: InputDecoration(
                                border: OutlineInputBorder(),
                                labelText: 'Date of Birth',
                                hintText: state._date,
                                suffixIcon: GestureDetector(
                                  child: Icon(Icons.calendar_today_outlined),
                                  onTap: state._showDatePicker,
                                )),
                          ),
                        ),
                        SizedBox(width: 30.0),
                        Expanded(
                          child: DropdownButtonFormField(
                            focusNode: state.genderFocusNode,
                            decoration: FormStyles.textFieldDecoration(
                                labelText: 'Gender'),
                            value: Gender.all[1],
                            onChanged: state._handleDropdownOnChanged,
                            onSaved: state.farmer.saveGender,
                            items: Gender.all
                                .map((e) => DropdownMenuItem(
                                      child: Text(e),
                                      value: e,
                                    ))
                                .toList(),
                          ),
                        ),
                        SizedBox(width: 30.0),
                        Expanded(
                          child: DropdownButtonFormField(
                            focusNode: state.ethnicityFocusNode,
                            decoration: FormStyles.textFieldDecoration(
                                labelText: 'Ethnicity'),
                            onChanged: state._handleDropdownOnChanged,
                            onSaved: state.farmer.saveGender,
                            items: Ethnicity.all
                                .map((e) => DropdownMenuItem(
                                      child: Text(e),
                                      value: e,
                                    ))
                                .toList(),
                          ),
                        ),
                        SizedBox(width: 30.0),
                        Expanded(
                          child: DropdownButtonFormField(
                            focusNode: state.maritalStatusFocusNode,
                            decoration: FormStyles.textFieldDecoration(
                                labelText: 'Marital Status'),
                            onChanged: state._handleDropdownOnChanged,
                            onSaved: state.farmer.saveGender,
                            items: MaritalStatus.all
                                .map((e) => DropdownMenuItem(
                                      child: Text(e),
                                      value: e,
                                    ))
                                .toList(),
                          ),
                        ),
                      ],
                    ),
                    TextFormField(
                      focusNode: state.addressFocusNode,
                      decoration:
                          FormStyles.textFieldDecoration(labelText: 'Address'),
                      textInputAction: TextInputAction.next,
                      autovalidateMode: AutovalidateMode.onUserInteraction,
                      validator: state.farmer.validateAddress,
                      onSaved: state.farmer.saveAddress,
                      maxLines: 5,
                      minLines: 2,
                    ),
                    Row(
                      children: [
                        // FARMER CATEGORY
                        Expanded(
                          child: DropdownButtonFormField(
                            focusNode: state.farmerCategoryFocusNode,
                            decoration: FormStyles.textFieldDecoration(
                                labelText: 'Farmer Category'),
                            onChanged: state._handleDropdownOnChanged,
                            onSaved: state.farmer.saveFarmerCategory,
                            items: FarmerCategory.all
                                .map((e) => DropdownMenuItem(
                                      child: Text(e),
                                      value: e,
                                    ))
                                .toList(),
                          ),
                        ),
                        SizedBox(width: 30.0),
                        // SUBSECTOR
                        Expanded(
                          child: DropdownButtonFormField(
                            focusNode: state.subsectorFocusNode,
                            decoration: FormStyles.textFieldDecoration(
                                labelText: 'Subsector'),
                            onChanged: state._handleDropdownOnChanged,
                            onSaved: state.farmer.saveSubsector,
                            items: Subsector.all
                                .map((e) => DropdownMenuItem(
                                      child: Text(e),
                                      value: e,
                                    ))
                                .toList(),
                          ),
                        ),
                        SizedBox(width: 30.0),
                        // OPERATION SCALE
                        Expanded(
                          child: DropdownButtonFormField(
                            focusNode: state.operationScaleFocusNode,
                            decoration: FormStyles.textFieldDecoration(
                                labelText: 'Operation Scale'),
                            onChanged: state._handleDropdownOnChanged,
                            onSaved: state.farmer.saveOperationScale,
                            items: OperationScale.all
                                .map((e) => DropdownMenuItem(
                                      child: Text(e),
                                      value: e,
                                    ))
                                .toList(),
                          ),
                        ),
                      ],
                    ),
                    SizedBox(
                      height: 15,
                    ),
                    Row(
                      children: [
                        Expanded(
                          child: FormField(builder: (builder) {
                            return CheckboxListTile(
                                title: Text('Head of Household'),
                                value: false,
                                onChanged: (bool) {});
                          }),
                        ),
                        Expanded(
                          child: FormField(builder: (builder) {
                            return CheckboxListTile(
                                title: Text('Farming Primary Income Source'),
                                value: false,
                                onChanged: (bool) {});
                          }),
                        ),
                        Expanded(
                          child: FormField(builder: (builder) {
                            return CheckboxListTile(
                                title: Text('Active Farmer'),
                                value: true,
                                onChanged: (bool) {});
                          }),
                        ),
                      ],
                    ),
                    SizedBox(
                      height: 15,
                    ),
                    ElevatedButton(
                        onPressed: () {}, child: Text('Register Farmer'))
                  ]),
                )
              ],
            )),
      ),
    );
  }
}
``` 

This code need to be refactored to improve readability and maintainability. I will refactor this code in a future post. 

Building this form made me realize the need to better understand how Layout and constraints in flutter works. We will build our capacity in this area in a future post as well.

##Wrap up

On Day 3, I built the Farmer Form but more importantly I realized the need to improve my knowledge of flutter layout and constraints.

Coming to flutter from a Django background made we realize the need of a dart package that automate the creation of forms from dart Models. This is a beautiful problem that I hope to solve in the future.

## Connect with me

Thank you for reading my post. Feel free to subscribe below to join me on the #100DaysOfCodeChallenge or connect with me on [LinkedIn](https://www.linkedin.com/in/curtlycritchlow/) and [Twitter](https://twitter.com/CritchlowCurtly).