0

I'm a beginner in flutter, I'm building a simple Note app where users can enter, edit and save the note in local db. I'm able to save the notes to DB but it is not fetched as soon as it is saved. I need to restart the app to see the note list. This is a Notes model class

import 'db_operations.dart';

class Note {
   int id;
   String title;
   String body;

  Note(this.id, this.title, this.body);

  Note.fromMap(Map<String, dynamic> map) {
    id = map['id'];
    title = map['title'];
    body = map['body'];
  }

  Map<String, dynamic> toMap(){
    return {
      DatabaseHelper.columnId : id,
      DatabaseHelper.columnTitle : title,
      DatabaseHelper.columnBody : body
    };
  }

  @override
  String toString(){
    return 'Note{title : $title, body : $body}';
  }
}

This is a Database helper class

import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'model_notes.dart';

class DatabaseHelper {

  static final _databaseName = "myNote.db";
  static final _databaseVersion = 1;
  static final table = 'notes_table';
  static final columnId = 'id';
  static final columnTitle = 'title';
  static final columnBody = 'body';

  DatabaseHelper._privateConstructor();
  static final DatabaseHelper instance = DatabaseHelper._privateConstructor();

  static Database _database;
  Future<Database> get database async {
    if (_database != null) return _database;
    // lazily instantiate the db the first time it is accessed
    _database = await initDatabase();
    return _database;
  }

  initDatabase() async {
    String path = join(await getDatabasesPath(), _databaseName);
    return await openDatabase(path,
        version: _databaseVersion,
        onCreate: _onCreate);
  }
  Future _onCreate(Database db, int version) async {
    await db.execute('''
          CREATE TABLE $table (
            $columnId INTEGER PRIMARY KEY AUTOINCREMENT,
            $columnTitle TEXT NOT NULL,
            $columnBody TEXT NOT NULL
          )
          ''');
  }

  Future<int> insert(Note note) async {
    Database db = await instance.database;
    if (note.title.trim().isEmpty) note.title = 'Untitled Note';
    return await db.insert(table, {'title': note.title, 'body': note.body});
  }
  Future<List<Note>> getNotesFromDB() async {
    final db = await database;
    List<Note> notesList = [];
    List<Map> maps = await db.query(table);
    if (maps.length > 0) {
      maps.forEach((map) {
        notesList.add(Note.fromMap(map));
      });
    }
    return notesList;
  }
}

This is where I am adding notes

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:note_taking_app/constants/buttons_and_icons_misc(classes).dart';
import 'package:note_taking_app/db/db_operations.dart';
import 'package:note_taking_app/db/model_notes.dart';
import 'package:sqflite/sqflite.dart';
import 'main_screen.dart';

final bodyController = TextEditingController();
final headerController = TextEditingController();
final dbHelper = DatabaseHelper.instance;

class AddingNotes extends StatefulWidget {
  @override
  _AddingNotesState createState() => _AddingNotesState();
}

class _AddingNotesState extends State<AddingNotes> {

  @override
  void initState() {
    super.initState();
    bodyController.clear();
    headerController.clear();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        elevation: 0,
        backwardsCompatibility: true,
        leading: LeadingIcon(
          callBack: () {
            Navigator.pop(context);
          },
        ),
        backgroundColor: Colors.white.withOpacity(0.4),
        actions: <Widget>[
          ActionsIconButton(
            icon: Icon(undo, color: black),
            callBack: () {
              debugPrint('undo tapped');
            },
          ),
          ActionsIconButton(
            icon: Icon(redo, color: black),
            callBack: () {
              debugPrint('redo tapped');
            },
          ),
          ActionsIconButton(
            icon: Icon(save, color: black),
            callBack: () async {
              debugPrint(bodyController.text);
              debugPrint(headerController.text);
              String title = headerController.text;
              String body =  bodyController.text;
              Note note = Note(20, title, body);
              var value = await dbHelper.insert(note);
              print("if 1 is return then insert success and 0 then not inserted : $value");
              Navigator.pop(context);
            },
          )
        ],
      ),
      body: Container(
        color: Colors.white.withOpacity(0.4),
        child: Padding(
          padding: const EdgeInsets.all(13.0),
          child: Column(
            children: [
              HeaderBody(
                textEditingController: headerController,
              ),
              SizedBox(
                height: 32.0,
              ),
              Expanded(
                child: NotesBody(
                  textEditingController: bodyController,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

This is where I am displaying notes

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:note_taking_app/constants/text_and_decorations(methods).dart';
import 'package:note_taking_app/db/model_notes.dart';
import 'package:note_taking_app/ui/adding_notes.dart';
import 'package:note_taking_app/db/db_operations.dart';

class MainScreen extends StatefulWidget {
  @override
  _MainScreenState createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {

  List<Note> noteList = [];

  @override
  void initState() {
    super.initState();
    dbHelper.initDatabase();
    setNotesFromDB();
  }

  setNotesFromDB() async{
    print("Entered setNotes");
    var fetchedNotes = await dbHelper.getNotesFromDB();
    setState(() {
      noteList = fetchedNotes;
    });
}

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        elevation: 0,
        title: titleText,
        backwardsCompatibility: false,
        automaticallyImplyLeading: false,
        backgroundColor: Colors.white.withOpacity(0.4),
      ),
      floatingActionButton: Container(
        height: 80.0,
        width: 80.0,
        child: FittedBox(
          child: FloatingActionButton(
            onPressed: () {
              Navigator.push(context,
                  MaterialPageRoute(builder: (context) => AddingNotes()));
            },
            child: const Icon(
              Icons.add,
            ),
            backgroundColor: Colors.green,
          ),
        ),
      ),
      body: ListView.builder(
        itemCount: noteList.length,
        itemBuilder: (context, index){
          return ListTile(
            title: Text('${noteList[index]}'),
          );
        },
      ),

    );
  }
}

When I restart the app I'm getting user-entered notes. How can I make this dynamic, as a user enters a note and save it, it should be displayed on Main Screen. but I don't know how to do that. Any help here guys, I'm stuck at this..

1 Answers1

0

The problem is that you are using a future, once it is complete there will be no updates, unless the Widget calling the getNotesFromDB() gets rebuild, which is the case when you restart the app or the emulator.

Moreover, you are also only fetching the notes in initState() of your MainScreen.

Option 1: Try turning your ListView.builder in the body into a streambuilder, which is refreshing your Screen whenever a new note is saved.

Option 2: Alternatively, implement a pull-to-refresh logic, which calls getNotesFromDB() for you. Checkout this video from the FlutterTeam to implement the feature.

Jahn E.
  • 1,228
  • 3
  • 6
  • 21