0

I have two screens, the HomePage and the Add screen. The app starts on the HomePage and has a Floating Action Button and a FutureBuilder. On clicking the FAB button, it goes to the Add screen, in which I can add details for another entry. On submitting, the data gets saved in the sqlite database and returns to the HomePage. But the FutureBuilder list is not rebuilding even upon calling setState. I am sure the database is updated upon entry creation, but is not reflected in the UI?

Any code improvement suggestions are also welcome!

Heres my HomePage.dart code

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  Future<List<Model>> getData() async {
    return await DatabaseHelper.instance.getModels();
  }

  Future? userFuture;

  @override
  void initState() {
    super.initState();
    userFuture = getData();
  }

  @override
  Widget build(BuildContext context) {
    print('Building listview');
    return Center(
      child: FutureBuilder<List<Model>>(
        future: userFuture as Future<List<Model>>,
        builder: ((context, AsyncSnapshot<List<Model>> snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.waiting:
              return const CircularProgressIndicator();
            default:
              if (snapshot.data!.isEmpty) {
                return Text('No data present');
              } else if (snapshot.hasData) {
                return ListView.builder(
                  itemCount: snapshot.data?.length,
                  itemBuilder: ((context, index) {
                    return MyCard(
                        key: ValueKey(snapshot.data![index].id),
                        snapshot.data![index].id,
                        snapshot.data![index].title,
                        snapshot.data![index].purpose);
                  }),
                );
              }
              return Text('data');
          }
        }),
      ),
    );
  }
}

Here's my Add.dart screen:

class AddEntry extends StatefulWidget {
  const AddEntry({super.key});

  @override
  State<AddEntry> createState() => _AddEntryState();
}

class _AddEntryState extends State<AddEntry> {
  final GlobalKey<FormState> _key = GlobalKey<FormState>();
  Map<String, String?> formField = <String, String?>{};

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('New Entry'),
      ),
      body: Form(
        key: _key,
        child: Column(
          children: [
            Flexible(
              child: MyTextField('Title', callback),
            ),
            Flexible(
              child: MyTextField('Purpose', callback),
            ),
            Flexible(
              child: MyTextField('Password', callback, obscure: true),
            ),
            TextButton(
              onPressed: () async {
                if (_key.currentState!.validate()) {
                  _key.currentState?.save();
                  formField.forEach((label, value) => print('$label = $value'));
                  await DatabaseHelper.instance.insertModel(Model(
                      id: null,
                      title: formField['Title'],
                      purpose: formField['Purpose'],
                      lastAccess: DateTime.now().toString(),
                      dateAdded: DateTime.now().toString(),
                      password: formField['Password']));
                  print(await DatabaseHelper.instance.getModels());
                  // await DatabaseHelper.instance.deleteAllData();
                  // print(await DatabaseHelper.instance.getModels());
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(
                      content: Text('Data Saved!'),
                      action: SnackBarAction(
                        label: 'Edit',
                        onPressed: () {
                          print('edit pressed!');
                        },
                      ),
                    ),
                  );
                  setState(() {
                    Navigator.pop(context);
                  });
                  //add logic to rebuild home screen after every addition of entry
                }
              },
              child: Text('Submit'),
            ),
          ],
        ),
      ),
    );
  }

  callback(varLabel, varValue) {
    formField[varLabel] = varValue;
  }
}

class MyTextField extends StatelessWidget {
  final String label;
  final bool obscure;
  final String? Function(String?) validation;
  final Function callback;

  const MyTextField(this.label, this.callback,
      {super.key, this.obscure = false, this.validation = validateText});

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      decoration: InputDecoration(
        labelText: label,
      ),
      validator: validation,
      obscureText: obscure,
      onSaved: ((String? val) => callback(label, val)),
    );
  }
}

String? validateText(String? formText) {
  if (formText!.isEmpty) return 'Field is required!';

  return null;
}

String? validateEmail(String? formEmail) {
  if (formEmail!.isEmpty) return 'E-Mail Address is required!';

  String pattern = r'\w+@\w+\.\w+';
  RegExp regexp = RegExp(pattern);
  if (!regexp.hasMatch(formEmail)) return 'Invalid E-Mail Address format!';

  return null;
}

String? validatePassword(String? password) {
  if (password!.isEmpty) return 'Password can\'t be empty!';

  String pattern =
      r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!@#\$&*~]).{8,}$';
  RegExp regexp = RegExp(pattern);
  if (!regexp.hasMatch(password)) {
    return 'Password must be atleast 8 characters, include an uppercase letter, number and symbol';
  }

  return null;
}

1 Answers1

0

In Future Builder future property you don't need to pass useFuture instead of that you call method which give you response something like getData. This will call your data and if data is present then it will show your data other wise something else which you want to show.

AJJ
  • 46
  • 3