fluttersqlitedartdesktop-applicationsyncfusion

How to list the data save in SQLite using Flutter


Currently, I am developing a desktop application in which I have saved the data in the database, now problem is that I am facing difficulties in listing the saved data on to screen. Below are the complete code files.

database_helper.dart

class DatabaseHelper {
  final databaseName = "auth.db";
  String newphase = '''
  CREATE TABLE IF NOT EXISTS newphase(
  srNo INTEGER PRIMARY KEY AUTOINCREMENT,
  phaseName TEXT,
  landinAcers INTEGER,
  landinmarlas INTEGER,
  description TEXT
  )
  ''';
Future<Database> initDB() async {
    print("initDB executed");
    try {
      String databaseName = 'auth.db';
      final databasePath = await getDatabasesPath();
      final path = join(databasePath, databaseName);
      return openDatabase(path, version: 2, onCreate: (db, version) async {
        await db.execute(newphase);
      });
    }catch (e) {
      print("Error initializing database: $e");
      rethrow;
    }
  }

 Future<int> addNewPhase(NewPhase newphase) async {
    final Database db = await initDB();
    return db.insert('newphase', newphase.toMap());
  }


  Future<List<Map<String, dynamic>>> getPhases() async {
    final Database db = await initDB();
    List<Map<String, Object?>> data = await db.query('newphase',);
    print("Data is " + data.toString());
    Map newPhase = data[0];
    print("Sr No is ${newphase[0].toString()}");
    print("Name is ${newphase[1].toString()}");
    return data;
  }
}

newphase_json.dart

    import 'dart:convert';

NewPhase newPhaseFromMap(String str) => NewPhase.fromMap(json.decode(str));

String newPhaseToMap(NewPhase data) => json.encode(data.toMap());

class NewPhase {
  final int? srNo;
  final String phaseName;
  final String landInAcers;
  final String landInMarlas;
  final String description;

  NewPhase({
    this.srNo,
    required this.phaseName,
    required this.landInAcers,
    required this.landInMarlas,
    required this.description,
  });

  factory NewPhase.fromMap(Map<String, dynamic> json) => NewPhase(
    srNo: json["srNo"],
    phaseName: json["phaseName"],
    landInAcers: json["landInAcers"],
    landInMarlas: json["landInMarlas"],
    description: json["description"],
  );

  Map<String, dynamic> toMap() => {
    "srNo": srNo,
    "phaseName": phaseName,
    "landInAcers": landInAcers,
    "landInMarlas": landInMarlas,
    "description": description,
  };
}

add_new_phase_form.dart

import '../../SQLite/newphase_json.dart';
import '../../utils/app_layout.dart';
import '../../utils/dependencies.dart';
import '../../widgets/elevated_button.dart';
import '../../SQLite/database_helper.dart';

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

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

class _AddNewPhaseFormState extends State<AddNewPhaseForm> {
  final _formKey = GlobalKey<FormState>();
  final phaseName = TextEditingController();
  final landInAcers = TextEditingController();
  final landInMarlas = TextEditingController();
  final description = TextEditingController();
  final DatabaseHelper db = DatabaseHelper();
  var homeController = Get.put(HomeController());

  addnewphase() async {
    var res = await db.addNewPhase(NewPhase(
      phaseName: phaseName.text,
      landInAcers: landInAcers.text, landInMarlas: landInMarlas.text,
        description: description.text,

    ));
    if (res > 0) {
      if (!mounted) return;
      homeController.changeIndex(1);
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Record added successfully!'),
          duration: Duration(seconds: 5), // Adjust duration as needed
        ),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    final size = AppLayout.getSize(context);
    return Container(
        width: size.width * 1,
        decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(15), color: Colors.white),
        child: Padding(
          padding: const EdgeInsets.all(15.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                'Add New Phase',
                style: TextStyle(
                  fontSize: 18,
                  fontFamily: 'Quicksand-SemiBold',
                  fontWeight: FontWeight.w500,
                  color: Colors.black,
                ),
              ),
              const SizedBox(height: 30),
              Form(
                key: _formKey,
                child: Column(
                  children: [
                    TextFormField(
                      controller: phaseName,
                      decoration: const InputDecoration(
                          labelText: 'Phase Name',
                        border: OutlineInputBorder(),
                      ),
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Please enter phase name';
                        }
                        return null;
                      },
                    ),
                    const SizedBox(height: 20),
                    TextFormField(
                      keyboardType: TextInputType.number,
                      controller: landInAcers,
                      decoration: const InputDecoration(labelText: 'Land In Acers', border: OutlineInputBorder(),),
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Please enter land in acers';
                        }
                        return null;
                      },
                    ),
                    const SizedBox(height: 20),
                    TextFormField(
                      controller: landInMarlas,
                      decoration: const InputDecoration(labelText: 'Land in Marlas', border: OutlineInputBorder(),),
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Please enter Land in Marlas';
                        }
                        return null;
                      },
                    ),
                    const SizedBox(height: 20),
                    TextFormField(
                      controller: description,
                      keyboardType: TextInputType.number,
                      decoration: const InputDecoration(labelText: 'Description', border: OutlineInputBorder(),),
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Please enter Description';
                        }
                        return null;
                      },
                    ),
                    const SizedBox(height: 20),
                    CustomElevatedButton(
                      width: 100,
                      height: 50,
                      backgroundColor: Colors.blue,
                      text: 'Add New',
                      style: const TextStyle(
                          fontSize: 16,
                          color: Colors.white,
                          fontFamily: 'Quicksand-SemiBold',
                          fontWeight: FontWeight.w500
                      ),
                      onPressed: (){
                        addnewphase();
                        print('record added...');
                      }
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
    );
  }
}

phase_list.dart

import '../../tabels/add_new_phase_list.dart';
import '../../utils/app_layout.dart';
import '../../utils/dependencies.dart';

class PhaseListScreen extends StatelessWidget {
  const PhaseListScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final size = AppLayout.getSize(context);
    return Padding(
      padding: const EdgeInsets.all(20.0),
      child: Scaffold(
          backgroundColor: const Color(0xffF2F7FB),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Row(
              children: [
                Container(
                  height: 45,
                  width: 45,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(5),
                    color: Colors.blue
                  ),
                  child: const Icon(Icons.landscape, color: Colors.white),
                ),
                const SizedBox(width: 20),
                const Text(
                  'Phase List',
                  style: TextStyle(
                    fontSize: 18,
                    fontFamily: 'Quicksand-SemiBold',
                    fontWeight: FontWeight.w500,
                    color: Colors.black,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 30),
            NewAddedPahseList(),
          ],
        )
      ),
    );
  }
}

add_new_phase_list.dart

 import 'package:flutter/cupertino.dart';
import 'package:new_city/SQLite/database_helper.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import '../utils/app_layout.dart';
import '../utils/dependencies.dart';


class NewAddedPahseList extends StatefulWidget {
  NewAddedPahseList({Key? key}) : super(key: key);

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

class _NewAddedPahseListState extends State<NewAddedPahseList> {
  late List<Map> newPhases;
  late PhasesDataSource phasesDataSource;
  var homeController = Get.put(HomeController());

  @override
  void initState() {
    super.initState();
    newPhases = getPhaseData() as List<Map>;
    phasesDataSource = PhasesDataSource(phaseData: newPhases);
  }

  final TextEditingController _searchController = TextEditingController();
  String _searchText = '';
  @override
  Widget build(BuildContext context) {
    final size = AppLayout.getSize(context);
    return Container(
      width: size.width * 1,
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(15), color: Colors.white),
      child: Padding(
        padding: const EdgeInsets.all(15.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            InkWell(
              onTap: () {
                homeController.changeIndex(30);
              },
              child: Container(
                width: 100,
                height: 45,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(5),
                  color: Colors.blue
                ),
                child: const Center(
                  child: Text(
                    'Add New',
                    style: TextStyle(
                        fontWeight: FontWeight.w400,
                        fontSize: 18,
                        fontFamily: 'Quicksand-Regular',
                        color: Colors.white
                    ),
                  ),
                ),
              ),
            ),
            const SizedBox(height: 30),
             Row(
               mainAxisAlignment: MainAxisAlignment.end,
              children: [
                SizedBox(
                  width: 300,
                  child: TextField(
                    controller: _searchController,
                    decoration: const InputDecoration(
                      labelText: 'Search',
                      hintText: 'Enter your search query',
                      border: OutlineInputBorder(),
                    ),
                    onChanged: (value) {
                      setState(() {
                        _searchText = value;
                      });
                    },
                  ),
                ),
              ],
            ),
            const SizedBox(height: 30),
            SfDataGrid(
              source: phasesDataSource,
              columnWidthMode: ColumnWidthMode.fill,
              allowSorting: true,
              allowMultiColumnSorting: true,
              sortingGestureType: SortingGestureType.tap,
              rowsPerPage: 0,
              columns: <GridColumn>[
                GridColumn(
                  columnName: 'serNo',
                  label: Container(
                    padding: const EdgeInsets.all(8.0),
                    alignment: Alignment.centerLeft,
                    child: const Text('Sr. No' , style:
                    TextStyle(
                      fontFamily: 'Quicksand-SemiBold',
                      fontSize: 18,
                      fontWeight: FontWeight.w500,
                      color: Colors.black,
                    ),),
                  ),
                ),
                GridColumn(
                  columnName: 'name',
                  label: Container(
                    padding: const EdgeInsets.all(8.0),
                    alignment: Alignment.centerLeft,
                    child: const Text('Phase Name', style:
                    TextStyle(
                      fontFamily: 'Quicksand-SemiBold',
                      fontSize: 18,
                      fontWeight: FontWeight.w500,
                      color: Colors.black,
                    ),
                    ),
                  ),
                ),
                GridColumn(
                    columnName: 't_area',
                    label: Container(
                        padding: const EdgeInsets.all(16.0),
                        alignment: Alignment.centerLeft,
                        child: const Text(
                          'Total Area in Acers',style:
                        TextStyle(
                          fontFamily: 'Quicksand-SemiBold',
                          fontSize: 18,
                          fontWeight: FontWeight.w500,
                          color: Colors.black,
                        ),
                        ))),
                GridColumn(
                    columnName: 't_plot',
                    label: Container(
                        padding: const EdgeInsets.all(8.0),
                        alignment: Alignment.centerLeft,
                        child: const Text(
                          'Total Plot', style:
                        TextStyle(
                          fontFamily: 'Quicksand-SemiBold',
                          fontSize: 18,
                          fontWeight: FontWeight.w500,
                          color: Colors.black,
                        ),
                          //overflow: TextOverflow.ellipsis,
                        ))),
             
                GridColumn(
                  columnName: 'action',
                  label: Container(
                    padding: const EdgeInsets.all(8.0),
                    alignment: Alignment.centerLeft,
                    child: const Text('Action' , style:
                    TextStyle(
                      fontFamily: 'Quicksand-SemiBold',
                      fontSize: 18,
                      fontWeight: FontWeight.w500,
                      color: Colors.black,
                    ),),
                  ),
                ),
              ],
            ),
            SfDataPager(pageCount: 5, delegate: DataPagerDelegate()),
          ],
        ),
      ),
    );
  }

  Future<List<Map>> getPhaseData() async {
    return await DatabaseHelper().getPhases();
  }
}

/// Custom business object class which contains properties to hold the detailed
/// information about the employee which will be rendered in datagrid.
class NewPhases {
  NewPhases(this.serNo, this.name, this.t_area,  this.t_plot,  this.price);
  final int serNo;
  final String name;
  final int t_area;
  final int t_plot;
  final int price;
}

/// An object to set the employee collection data source to the datagrid. This
/// is used to map the employee data to the datagrid widget.
class PhasesDataSource extends DataGridSource {
  /// Creates the employee data source class with required details.
  PhasesDataSource({required List<Map> phaseData}) {
    _phaseData = phaseData
    .map<DataGridRow>((e) => DataGridRow(cells: [
    DataGridCell<int>(columnName: 'serNo', value: e.length),
    DataGridCell<String>(columnName: 'name', value: e.toString()),
    DataGridCell<int>(columnName: 't_area', value: e.length),
    DataGridCell<int>(columnName: 't_plot', value: e.length),
    DataGridCell<int>(columnName: 'action', value: e.length),
    ])).toList();
  }

  List<DataGridRow> _phaseData = [];

  @override
  List<DataGridRow> get rows => _phaseData;

  @override
  DataGridRowAdapter buildRow(DataGridRow row) {
    return DataGridRowAdapter(
        cells: row.getCells().map<Widget>((e) {
          return Container(
            alignment: Alignment.topLeft,
            padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 15),
            child:e.columnName == 'action'?Row(
              children: [
                GestureDetector(
                  onTap: (){},
                  child: const Icon(Icons.edit, color: Colors.blue,),
                ),
                const SizedBox(width:10),
                GestureDetector(
                  onTap: (){},
                  child: const Icon(Icons.delete, color: Colors.red,),
                ),
              ],
            ):Text(e.value.toString(), style: const TextStyle(
              fontFamily: 'Quicksand-Regular',
              fontSize: 16,
              fontWeight: FontWeight.w400,
              color: Color(0xff2f2e2e),
            ),
            ),
          );
        }).toList());
  }
}

Currently, the data is saving successfully but faces an issue in listing the data


Solution

  • the initState method cannot be async

    so,on your NewAddedPahseList widget

    create a new method like this

    fetchInitData() async {
    newPhases =await  getPhaseData();
    phasesDataSource = PhasesDataSource(phaseData: newPhases); 
    setState((){});
    }
    

    and call this method on initState

    @override
     void initState() {
      phasesDataSource = PhasesDataSource(phaseData: newPhases); 
      fetchInitData();
     super.initState();    
    }
    

    You need to handle the asynchronous nature of the Future to access its value.

    and replace

     late List<Map> newPhases;
    

    by:

    List<Map> newPhases=[];