sqflite_state_repository 1.0.3

  • Readme
  • Changelog
  • Example
  • Installing
  • new65

sqflite_state_repository #

This package encapsulates Sqflite Table defined by RowModel, it encapsulats all the CRUD operations

Getting Started #

First we define the table Structure using Tabledef and Fieldefs

// It defines the table and fields that que repository creates // and manage CRUD operations // / // dart // table = TableDef(tableName: 'notes', fields: [ // FieldDef('id', DbType.integer, // primaryKey: true, // primaryKeyType: PrimaryKeyType.integer_auto_incremental), // FieldDef('title', DbType.text), // FieldDef('description', DbType.text), // FieldDef('priority', DbType.integer), // FieldDef('date', DbType.datetime) //

After we define the RowModel

Must create the props and implement

class Note extends RowModel{

  int get id => this['id'] ;
	String get title => this['title'];
  String get description => this['description'];
  int get priority => this['priority'];
  DateTime get date =>this['date'];

	set title(String newTitle) {
		if (newTitle.length <= 255) {
			this['title'] = newTitle;
		}
	}
  set description(String newDescription) {
		if (newDescription.length <= 255) {
			this['description'] = newDescription;
		}
	}
	set priority(int newPriority) {
		if (newPriority >= 1 && newPriority <= 2) {
			this['priority'] = newPriority;
		}
	}
	set date(DateTime newDate) {
		this['date'] = newDate;
	}

	Note(TableDef tableDef, [title, date, priority, description]) : super(tableDef)
  {
     if(!loaded())
      this.newRecord();
		this['title'] = title;
		this['description'] = description;
		this['priority'] = priority;
		this['date'] = date;   
  }
}

At last we inherit from SqfRepository

 class NoteRepository extends SqfRepository<Note> {
   NoteRepository() : super();

 Note addNew(String title, DateTime date, int priority, [String description]) {
   Note newNote = Note(this.table, title, date, priority, description);
   rows.add(newNote);
   this.current = newNote;
   return newNote;
 }


Define the table structure and when the class its instantiate, it creates the table

   @override
   getTableDefiniton() {
     table = TableDef(tableName: 'notes', fields: [
       FieldDef('id', DbType.integer,
           primaryKey: true,
           primaryKeyType: PrimaryKeyType.integer_auto_incremental),
       FieldDef('title', DbType.text),
       FieldDef('description', DbType.text),
       FieldDef('priority', DbType.integer),
       FieldDef('date', DbType.datetime)
     ]);
   }

   @override
   Note getNewRow() {
     return Note(table);
   }
 }

Then we can use in widgets and sign for change notifications Code for list


class NoteListState extends NotifiableState<NoteList> {
  NoteRepository noteRepo;
  @override
  void initState() {
    noteRepo = NoteRepository();
    noteRepo.addListener(this);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text('Notes'),
      ),
      body: getNoteListView(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          debugPrint('FAB clicked');
          noteRepo.addNew('',DateTime.now(),2);
          navigateToDetail('Add Note');
        },
        tooltip: 'Add Note',
        child: Icon(Icons.add),
      ),
    );
  }

  ListView getNoteListView() {
    TextStyle titleStyle = Theme.of(context).textTheme.subhead;
    
    return ListView.builder(
      itemCount: noteRepo.rows.length,
      itemBuilder: (BuildContext context, int position) {
        return Card(
          color: Colors.white,
          elevation: 2.0,
          child: ListTile(
            leading: CircleAvatar(
              backgroundColor:
                     getPriorityColor(noteRepo.rows[position]['priority']),
              child: getPriorityIcon(noteRepo.rows[position]['priority']),
            ),
            title: Text(
              //noteRepo.rows[position]['title'] work's this way either
              noteRepo.rows[position].title,
              style: titleStyle,
            ),
            subtitle: Text(DateFormat.yMMMMd().format(noteRepo.rows[position].date)),
            trailing: GestureDetector(
              child: Icon(
                Icons.delete,
                color: Colors.grey,
              ),
              onTap: () {
                _delete(context, noteRepo.rows[position]);
              },
            ),
            onTap: () {
              debugPrint("ListTile Tapped");
              noteRepo.setCurrent(noteRepo.rows[position]);
              navigateToDetail('Edit Note');
            },
          ),
        );
      },
    );
  }

  // Returns the priority color
  Color getPriorityColor(int priority) {
    switch (priority) {
      case 1:
        return Colors.red;
        break;
      case 2:
        return Colors.yellow;
        break;

      default:
        return Colors.yellow;
    }
  }

  // Returns the priority icon
  Icon getPriorityIcon(int priority) {
    switch (priority) {
      case 1:
        return Icon(Icons.play_arrow);
        break;
      case 2:
        return Icon(Icons.keyboard_arrow_right);
        break;

      default:
        return Icon(Icons.keyboard_arrow_right);
    }
  }

  void _delete(BuildContext context, Note note) async {
    int result = await noteRepo.delete(note);
    if (result == 1) {
      _showSnackBar(context, 'Note Deleted Successfully');
    }
  }

  void _showSnackBar(BuildContext context, String message) {
    final snackBar = SnackBar(content: Text(message));
    Scaffold.of(context).showSnackBar(snackBar);
  }

  void navigateToDetail(String title) async {
        await Navigator.push(context, MaterialPageRoute(builder: (context) {
      return NoteDetail(title);
    }));
  }

Code for detail

class NoteDetail extends StatefulWidget {

	final String appBarTitle;
	Note note;

	NoteDetail(this.appBarTitle);

	@override
  NotifiableState<StatefulWidget> createState() {

    return NoteDetailState(this.appBarTitle);
  }
}

class NoteDetailState extends NotifiableState<NoteDetail> {

	static var _priorities = ['High', 'Low'];

	String appBarTitle;
	Note note;

	TextEditingController titleController = TextEditingController();
	TextEditingController descriptionController = TextEditingController();

	NoteDetailState(this.appBarTitle);

@override
  void initState() {
    note = Repository.of<NoteRepository>().current;
    super.initState();
  }

	@override
  Widget build(BuildContext context) {

		TextStyle textStyle = Theme.of(context).textTheme.title;

		titleController.text = note.title;
		descriptionController.text = note.description;

    return WillPopScope(

	    onWillPop: () {
	    	// Write some code to control things, when user press Back navigation button in device navigationBar
		    moveToLastScreen();
	    },

	    child: Scaffold(
	    appBar: AppBar(
		    title: Text(appBarTitle),
		    leading: IconButton(icon: Icon(
				    Icons.arrow_back),
				    onPressed: () {
		    	    // Write some code to control things, when user press back button in AppBar
		    	    moveToLastScreen();
				    }
		    ),
	    ),

	    body: Padding(
		    padding: EdgeInsets.only(top: 15.0, left: 10.0, right: 10.0),
		    child: ListView(
			    children: <Widget>[

			    	// First element
				    ListTile(
					    title: DropdownButton(
							    items: _priorities.map((String dropDownStringItem) {
							    	return DropdownMenuItem<String> (
									    value: dropDownStringItem,
									    child: Text(dropDownStringItem),
								    );
							    }).toList(),

							    style: textStyle,

							    value: getPriorityAsString(note.priority),

							    onChanged: (valueSelectedByUser) {
							    	setState(() {
							    	  debugPrint('User selected $valueSelectedByUser');
							    	  updatePriorityAsInt(valueSelectedByUser);
							    	});
							    }
					    ),
				    ),

				    // Second Element
				    Padding(
					    padding: EdgeInsets.only(top: 15.0, bottom: 15.0),
					    child: TextField(
						    controller: titleController,
						    style: textStyle,
						    onChanged: (value) {
						    	debugPrint('Something changed in Title Text Field');
						    	updateTitle();
						    },
						    decoration: InputDecoration(
							    labelText: 'Title',
							    labelStyle: textStyle,
							    border: OutlineInputBorder(
								    borderRadius: BorderRadius.circular(5.0)
							    )
						    ),
					    ),
				    ),

				    // Third Element
				    Padding(
					    padding: EdgeInsets.only(top: 15.0, bottom: 15.0),
					    child: TextField(
						    controller: descriptionController,
						    style: textStyle,
						    onChanged: (value) {
							    debugPrint('Something changed in Description Text Field');
							    updateDescription();
						    },
						    decoration: InputDecoration(
								    labelText: 'Description',
								    labelStyle: textStyle,
								    border: OutlineInputBorder(
										    borderRadius: BorderRadius.circular(5.0)
								    )
						    ),
					    ),
				    ),

				    // Fourth Element
				    Padding(
					    padding: EdgeInsets.only(top: 15.0, bottom: 15.0),
					    child: Row(
						    children: <Widget>[
						    	Expanded(
								    child: RaisedButton(
									    color: Theme.of(context).primaryColorDark,
									    textColor: Theme.of(context).primaryColorLight,
									    child: Text(
										    'Save',
										    textScaleFactor: 1.5,
									    ),
									    onPressed: () {

									    	  debugPrint("Save button clicked");
									    	  _save();
									    },
								    ),
							    ),

							    Container(width: 5.0,),

							    Expanded(
								    child: RaisedButton(
									    color: Theme.of(context).primaryColorDark,
									    textColor: Theme.of(context).primaryColorLight,
									    child: Text(
										    'Delete',
										    textScaleFactor: 1.5,
									    ),
									    onPressed: () {
											    debugPrint("Delete button clicked");
											    _delete();
									    },
								    ),
							    ),

						    ],
					    ),
				    ),

			    ],
		    ),
	    ),

    ));
  }

  void moveToLastScreen() {
		Navigator.pop(context, true);
  }

	// Convert the String priority in the form of integer before saving it to Database
	void updatePriorityAsInt(String value) {
		switch (value) {
			case 'High':
				note.priority = 1;
				break;
			case 'Low':
				note.priority = 2;
				break;
		}
	}

	// Convert int priority to String priority and display it to user in DropDown
	String getPriorityAsString(int value) {
		String priority;
		switch (value) {
			case 1:
				priority = _priorities[0];  // 'High'
				break;
			case 2:
				priority = _priorities[1];  // 'Low'
				break;
		}
		return priority;
	}

	// Update the title of Note object
  void updateTitle(){
    note.title = titleController.text;
  }

	// Update the description of Note object
	void updateDescription() {
		note.description = descriptionController.text;
	}

	// Save data to database
	void _save() async {

		moveToLastScreen();

		note.date = DateTime.now();
		int result;
		if (note.id != null) {  // Case 1: Update operation
			result = await Repository.of<NoteRepository>().update(note);
		} else { // Case 2: Insert Operation
			result = await Repository.of<NoteRepository>().insert(note);
		}

		if (result != 0) {  // Success
			_showAlertDialog('Status', 'Note Saved Successfully');
		} else {  // Failure
			_showAlertDialog('Status', 'Problem Saving Note');
		}

	}

	void _delete() async {

		moveToLastScreen();

		// Case 1: If user is trying to delete the NEW NOTE i.e. he has come to
		// the detail page by pressing the FAB of NoteList page.
		if (note.id == null) {
			_showAlertDialog('Status', 'No Note was deleted');
			return;
		}

		// Case 2: User is trying to delete the old note that already has a valid ID.
		int result =await Repository.of<NoteRepository>().delete(note);
		if (result != 0) {
			_showAlertDialog('Status', 'Note Deleted Successfully');
		} else {
			_showAlertDialog('Status', 'Error Occured while Deleting Note');
		}
	}

	void _showAlertDialog(String title, String message) {

		AlertDialog alertDialog = AlertDialog(
			title: Text(title),
			content: Text(message),
		);
		showDialog(
				context: context,
				builder: (_) => alertDialog
		);
	}

}

[1.0.3] - Fix return type. [1.0.1] - Fire some notifications. [1.0.0] - Initial Release.

example/README.md

notes #

A new Flutter project.

Getting Started #

This project is a starting point for a Flutter application.

A few resources to get you started if this is your first Flutter project:

For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  sqflite_state_repository: ^1.0.3

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:sqflite_state_repository/sqflite_state_repository.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
32
Health:
Code health derived from static analysis. [more]
97
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
65
Learn more about scoring.

We analyzed this package on Jan 19, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.0
  • pana: 0.13.4
  • Flutter: 1.12.13+hotfix.5

Health issues and suggestions

Document public APIs. (-1 points)

79 out of 79 API elements have no dartdoc comment.Providing good documentation for libraries, classes, functions, and other API elements improves code readability and helps developers find and use your API.

Fix lib/src/SqfRepository.dart. (-1.99 points)

Analysis of lib/src/SqfRepository.dart reported 4 hints:

line 53 col 15: Avoid wrapping fields in getters and setters just to be "safe".

line 57 col 7: Avoid wrapping fields in getters and setters just to be "safe".

line 63 col 9: Avoid wrapping fields in getters and setters just to be "safe".

line 65 col 7: Avoid wrapping fields in getters and setters just to be "safe".

Format lib/src/Model.dart.

Run flutter format to format lib/src/Model.dart.

Format lib/src/db_helper.dart.

Run flutter format to format lib/src/db_helper.dart.

Format lib/src/tabledefs.dart.

Run flutter format to format lib/src/tabledefs.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
path ^1.6.4 1.6.4
sqflite ^1.2.0 1.2.0
state_repository ^1.0.0 1.0.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.8
sky_engine 0.0.99
synchronized 2.1.1
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test