Notes App using Bloc State Management (Data Add, Fetch, Delete in Sqflite Database)

 import 'dart:io';

import 'package:bloc_wslc_statemanagement/NotesApp_Bloc/Models/noteModel.dart';
import "package:path/path.dart";
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';

class DbHelper {
static final DbHelper dbHelper = DbHelper();
Database? database;
static const Note_table = "notes";
static const Note_id = "noteid";
static const Note_title = "notetitle";
static const Note_desc = "notedesc";

Future<Database> getDb() async {
if (database != null) {
return database!;
} else {
return await initDb();
}
}

Future<Database> initDb() async {
Directory directory = await getApplicationDocumentsDirectory();
var dbpath = join(directory.path + "notesdb2.db");
return openDatabase(
dbpath,
version: 1,
onCreate: (db, version) {
return db.execute(
"create table $Note_table ($Note_id integer primary key autoincrement,"
" $Note_title text, $Note_desc text)");
},
);
}

Future<bool> addNotes(NotesModel newuser) async {
var db = await getDb();
int inserteddata = await db.insert(Note_table, newuser.toMap());
return inserteddata > 0;
}

Future<List<NotesModel>> fetchData() async {
var db = await getDb();
List<Map<String, dynamic>> notes = await db.query(Note_table);
List<NotesModel> listNotes = [];

for (Map<String, dynamic> notesmodel in notes) {
NotesModel newnote = NotesModel.fromMap(notesmodel);
listNotes.add(newnote);
}
return listNotes;
}

Future<bool> DeleteNotes(int id) async {
var db = await getDb();
var count = await db.delete(Note_table, where: "$Note_id=?", whereArgs: [id.toString()]);
return count > 0;
}
}
import 'package:bloc_wslc_statemanagement/NotesApp_Bloc/Database/dbhelper.dart';

class NotesModel {
int? id;
String title;
String desc;

NotesModel({this.id, required this.title, required this.desc});

/// When data will go(data will Add) in database at that time, we will use toMap() function(toMap -> insert)
/// When data will fetch from database at that time, we will use fromMap() function(fromMap -> fetch)
/// When we work with API, at that time, we will use toJson() and fromJson() method

/// Use of "factory" keyword : When data will go in database and when data will fetch from database,
/// at that time small amount of data will be stored in "factory" keyword.

/// To get data(fetch data) from database, fromMap() method is used as shown below:
factory NotesModel.fromMap(Map<String, dynamic> mapdata) {
return NotesModel(
id: mapdata[DbHelper.Note_id],
title: mapdata[DbHelper.Note_title],
desc: mapdata[DbHelper.Note_desc]);
}

/// To Add data(store data) in database, toMap() method is used as shown below:
Map<String, dynamic> toMap() {
return {
DbHelper.Note_id: id,
DbHelper.Note_title: title,
DbHelper.Note_desc: desc,
};
}
}

import "dart:developer";
import "package:bloc_wslc_statemanagement/NotesApp_Bloc/Blocs/notes_bloc.dart";
import "package:bloc_wslc_statemanagement/NotesApp_Bloc/Blocs/notes_events.dart";
import "package:bloc_wslc_statemanagement/NotesApp_Bloc/Models/noteModel.dart";
import "package:bloc_wslc_statemanagement/NotesApp_Bloc/Widgets/uihelper.dart";
import "package:flutter/material.dart";
import "package:provider/provider.dart";

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

@override
State<AddDataScreen> createState() {
return AddDataScreenState();
}
}

class AddDataScreenState extends State<AddDataScreen> {
TextEditingController titleController = TextEditingController();
TextEditingController descController = TextEditingController();

@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
return FocusManager.instance.primaryFocus?.unfocus();
},
child: Scaffold(
appBar: AppBar(
title: const Text(
"Add Data Screen",
style: TextStyle(fontWeight: FontWeight.bold),
),
centerTitle: true,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
UiHelper.customTextFormField(
titleController,
"Enter the title",
Icons.title,
),
UiHelper.customTextFormField(
descController,
"Enter the description",
Icons.description,
),
const SizedBox(height: 50.0),
ElevatedButton(
onPressed: () {
context.read<NotesBloc>().add(
NotesAddEvent(
newnote: NotesModel(
title: titleController.text.toString(),
desc: descController.text.toString(),
),
),
);
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
fixedSize: const Size(350.0, 50.0),
backgroundColor: Colors.blue,
shape: const LinearBorder(),
),
child: const Text(
"Add Data",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 20.0),
),
),
],
),
),
);
}
}

import "package:bloc_wslc_statemanagement/NotesApp_Bloc/Blocs/notes_bloc.dart";
import "package:bloc_wslc_statemanagement/NotesApp_Bloc/Blocs/notes_events.dart";
import "package:bloc_wslc_statemanagement/NotesApp_Bloc/Blocs/notes_states.dart";
import "package:bloc_wslc_statemanagement/NotesApp_Bloc/Database/dbhelper.dart";
import "package:bloc_wslc_statemanagement/NotesApp_Bloc/Screens/adddatascreen.dart";
import "package:flutter/material.dart";
import "package:flutter_bloc/flutter_bloc.dart";

void main() {
runApp(const MyApp());
}

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

@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) {
return NotesBloc(dbHelper: DbHelper.dbHelper);
},
child: MaterialApp(
title: "Notes App",
debugShowCheckedModeBanner: false,
theme: ThemeData(
appBarTheme: const AppBarTheme(
backgroundColor: Colors.grey,
centerTitle: true,
),
),
home: const NotesApp(),
),
);
}
}

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

@override
State<NotesApp> createState() {
return NotesAppState();
}
}

class NotesAppState extends State<NotesApp> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
"Notes App",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const AddDataScreen();
},
),
);
},
backgroundColor: Colors.blue,
child: const Icon(Icons.add, color: Colors.white, size: 30.0),
),
body: BlocBuilder<NotesBloc, NotesStates>(
builder: (context, state) {
if (state is NotesLoadingState) {
return const Center(
child: CircularProgressIndicator(),
);
} else if (state is NotesLoadedState) {
return ListView.builder(
itemCount: state.arrNotes.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Text(
"${index + 1}",
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 20.0),
),
title: Text(
state.arrNotes[index].title,
style: const TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(state.arrNotes[index].desc),
trailing: IconButton(
onPressed: () {
context.read<NotesBloc>().add(
NotesDeleteEvent(
id: state.arrNotes[index].id!.toInt()),
);
},
icon: const Icon(Icons.delete, color: Colors.red),
),
),
);
},
);
} else if (state is NotesErrorState) {
return Center(
child: Text(state.errormsg.toString()),
);
} else {
return const Center(
child: Text("No Data Found!!"),
);
}
},
),
);
}
}

import "package:flutter/material.dart";

class UiHelper {
static customTextFormField(
TextEditingController controller, String text, IconData iconData) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0, vertical: 15.0),
child: TextFormField(
controller: controller,
decoration: InputDecoration(
hintText: text,
suffixIcon: Icon(iconData),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
),
);
}
}

import 'package:bloc_wslc_statemanagement/NotesApp_Bloc/Models/noteModel.dart';

abstract class NotesStates {}

class NotesInitialState extends NotesStates {}

class NotesLoadingState extends NotesStates {}

class NotesLoadedState extends NotesStates {
List<NotesModel> arrNotes;

NotesLoadedState({required this.arrNotes});
}

class NotesErrorState extends NotesStates {
String errormsg;

NotesErrorState({required this.errormsg});
}

import 'package:bloc_wslc_statemanagement/NotesApp_Bloc/Models/noteModel.dart';

abstract class NotesEvents {}

class NotesAddEvent extends NotesEvents {
NotesModel newnote;

NotesAddEvent({required this.newnote});
}

class NotesFetchEvent extends NotesEvents {}

class NotesDeleteEvent extends NotesEvents {
int id;

NotesDeleteEvent({required this.id});
}

import "package:bloc_wslc_statemanagement/NotesApp_Bloc/Blocs/notes_events.dart";
import "package:bloc_wslc_statemanagement/NotesApp_Bloc/Blocs/notes_states.dart";
import "package:bloc_wslc_statemanagement/NotesApp_Bloc/Database/dbhelper.dart";
import "package:flutter_bloc/flutter_bloc.dart";

class NotesBloc extends Bloc<NotesEvents, NotesStates> {
DbHelper dbHelper;

NotesBloc({required this.dbHelper}) : super(NotesInitialState()) {
/// Add Data in Database
on<NotesAddEvent>(
(event, emit) async {
emit(NotesLoadingState());
bool check = await dbHelper.addNotes(event.newnote);
if (check) {
var arrnotes = await dbHelper.fetchData();
emit(NotesLoadedState(arrNotes: arrnotes));
} else {
emit(NotesErrorState(errormsg: "An Error Occurred!"));
}
},
);

/// Get all Notes
on<NotesFetchEvent>(
(event, emit) async {
emit(NotesLoadingState());
var arrNotes = await dbHelper.fetchData();
emit(NotesLoadedState(arrNotes: arrNotes));
},
);

/// Delete Notes
on<NotesDeleteEvent>(
(event, emit) async {
emit(NotesLoadingState());
await dbHelper.DeleteNotes(event.id);
var arrnotes = await dbHelper.fetchData();
emit(NotesLoadedState(arrNotes: arrnotes));
},
);
}
}





Comments

Popular posts from this blog

Second GET API Calling with Bloc simple Example in Flutter

Stack Container Scrollable Card widget UI with Custom Widget

Pagination with Bloc Pattern in Flutter