My goal is restoring data from sql database to Listview. Firstly, I started with creating database and model class. Secondly I realized that I have to use FutureBuilder. But I can't understood, how to use this stuff in my case. In addition I have known, that have to use GlobalKey.
This is my code. In this version of my code, Alert dialog doesn't work
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:path/path.dart';
import 'dart:ui';
import 'package:samuraigym/program_training_handler.dart';
import 'package:samuraigym/my_icons_icons.dart' as custicon;
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:async';
import 'dart:io' as io;
import 'package:fluttertoast/fluttertoast.dart';
class MeasurementsScreen extends StatefulWidget {
#override
_MeasurementsScreenState createState() => _MeasurementsScreenState();
}
class _MeasurementsScreenState extends State<MeasurementsScreen> {
List<ListItem> listItems;
final scaffoldKey = new GlobalKey<ScaffoldState>();
final formKey = new GlobalKey<FormState>();
String typeOfMuscle;
String numberOfMuscle;
var nameItem = ["Рост","Вес","Шея","Плечевой пояс","Грудь","Бицепс",
"Предплечье","Запястье","Живот","Бедро","Голень","Лодыжка"];
#override
void initState() {
super.initState();
initListItems();
}
void initListItems() {
listItems = [
new ListItem(
detail: nameItem[0],
index: 0,
data: " "),
new ListItem(
detail: nameItem[1],
index: 1,
data: " "),
new ListItem(
detail: nameItem[2],
index: 2,
data: " "),
new ListItem(
detail: nameItem[3],
index: 3,
data: " "),
new ListItem(
detail: nameItem[4],
index: 4,
data: " "),
new ListItem(
detail: nameItem[5],
index: 5,
data: " "),
new ListItem(
detail: nameItem[6],
index: 6,
data: " "),
new ListItem(
detail: nameItem[7],
index: 7,
data: " "),
new ListItem(
detail: nameItem[8],
index: 8,
data: " "),
new ListItem(
detail: nameItem[9],
index: 9,
data: " "),
new ListItem(
detail: nameItem[10],
index: 10,
data: " "),
new ListItem(
detail: nameItem[11],
index: 11,
data: " ")
];
}
void sumbitContact(int index, String numberOfMuscle) {
if(this.formKey.currentState.validate())
formKey.currentState.save();
else
return null;
var measurementsDatabaseModel = MeasurementsDatabaseModel();
measurementsDatabaseModel.numberOfMuscle = numberOfMuscle;
measurementsDatabaseModel.typeOfMuscle = index as String;
var dbHelper = DatabaseHelperForMeasurements();
dbHelper.addNewMeasurementsDatabaseModel(measurementsDatabaseModel);
Fluttertoast.showToast(msg: 'Contact was saved',
toastLength: Toast.LENGTH_SHORT);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
key: scaffoldKey,
backgroundColor: Color(0xff2b2b2b),
appBar: AppBar(
backgroundColor: Colors.lightGreen[400],
title: Text(
'Замеры',
style: new TextStyle(
color: Colors.white
),),
leading: IconButton(
icon:Icon(Icons.arrow_back),
color: Colors.white ,
onPressed:() => Navigator.of(context).pop(),
),
),
body: FutureBuilder<List<MeasurementsDatabaseModel>>(
future: getMeasurementsDatabaseModelFromDB(),
builder: (context, snapshot){
if(snapshot.data != null && snapshot.hasData){
return ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index) => listItems[index],
);
} else {
return ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index) => listItems[index],
);
}
}
)
);
}
}
Future<List<MeasurementsDatabaseModel>> getMeasurementsDatabaseModelFromDB() async {
var dbHelper = DatabaseHelperForMeasurements();
Future<List<MeasurementsDatabaseModel>> contacts = dbHelper.getMeasurementsDatabaseModel();
return contacts;
}
class ListItem extends StatefulWidget {
String detail;
int index;
String data;
_MeasurementsScreenState measurementsScreen;
ListItem({Key key, this.detail, this.index, this.data}) : super(key: key);
#override
_ListItem createState() => _ListItem(measurementsScreen);
}
class _ListItem extends State<ListItem> {
bool isAppear = false;
final _MeasurementsScreenState measurementsScreen;
DatabaseHelperForMeasurements db = DatabaseHelperForMeasurements();
_ListItem(this.measurementsScreen);
MeasurementsDatabaseModel measurementsDatabaseModel = new MeasurementsDatabaseModel();
String typeOfMuscle;
String numberOfMuscle;
String lastSelectedValue;
var name = ["Рост","Вес","Шея","Плечевой пояс","Грудь","Бицепс",
"Предплечье","Запястье","Живот","Бедро","Голень","Лодыжка"];
var indication = ["Ваш рост","Ваш вес","Ваша шея","Ваш плечевой пояс","Ваша грудь","Ваш бицепс",
"Ваше предплечье","Ваше запястье","Ваш живот","Ваше бедро","Ваша голень","Ваша лодыжка"];
var prefix = ["см: ","кг: ","см: ","см: ","см: ","см: ","см: ","см: ","см: ","см: ","см: ","см: "];
var prefixAlert = ["см","кг","см","см","см","см","см","см","см","см","см","см"];
TextEditingController customcintroller;
Future<String> createAlertDialog(BuildContext context, int indexAl) async{
customcintroller = TextEditingController();
String returnVal = await showDialog(
context: context, builder: (context){
return AlertDialog(
title: Text(name[indexAl]),
content: TextFormField(
textDirection: TextDirection.ltr,
controller: customcintroller,
style: TextStyle(
color: Colors.lightGreen[400],
fontSize: 18.5),
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 4.0),
labelText: indication[indexAl],
suffixText: prefixAlert[widget.index],
alignLabelWithHint: false,
),
keyboardType: TextInputType.phone,
textInputAction: TextInputAction.done,
onSaved: (val) => this.numberOfMuscle = val,
),
actions: <Widget>[
FlatButton(
child: const Text('ОТМЕНА'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: const Text('ОК'),
onPressed: () {
setState(() {
widget.data = customcintroller.text.toString();
isAppear = !isAppear;
measurementsScreen.sumbitContact(widget.index, widget.data);
getMeasurementsDatabaseModelFromDB();
Navigator.of(context).pop();
});
},
),
],
);
});
return returnVal;
}
#override
Widget build(BuildContext context) {
return Container(
child: GestureDetector(
onTap: () {
createAlertDialog(context, widget.index);
},
child: Container(
color: Color(0xff2b2b2b),
height: 55.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
// Padding(
// padding: const EdgeInsets.all(8.0),
// child: Icon(
// custicon.MyIcons.bathroom_scale,
// color: Colors.lightGreen[400],
// size: 40.0)),
Padding(
padding: const EdgeInsets.all(16.0),
child: new Text(
widget.detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
),
Container(
alignment: Alignment.centerRight,
child: isAppear ? Padding(
padding: EdgeInsets.all(8.0),
child: Container(
decoration: ShapeDecoration(
color: Colors.lightGreen[400],
shape: RoundedRectangleBorder(
side: BorderSide(width: 1.0, style: BorderStyle.solid, color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(5.0)),
),
),
child: Padding(
padding: EdgeInsets.all(4.0),
child: new Text(
prefix[widget.index] + widget.data,
style: new TextStyle(
fontSize: 16.0,
color: Colors.white
),
)))) : SizedBox(),
)
],
),
),
),
),
],
),
)));
}
}
class MeasurementsDatabaseModel{
int id;
String typeOfMuscle;
String numberOfMuscle;
MeasurementsDatabaseModel();
}
class DatabaseHelperForMeasurements{
static Database db_instance;
final String TABLE_NAME = "Measurements";
Future<Database> get db async{
if(db_instance == null)
db_instance = await initDB();
return db_instance;
}
initDB() async {
io.Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path,"Measurements_db.db");
var db = await openDatabase(path,version: 1, onCreate: onCreateFunc);
return db;
}
void onCreateFunc(Database db, int version) async{
await db.execute('CREATE TABLE $TABLE_NAME(id INTEGER PRIMARY KEY AUTOINCREMENT, typeOfMuscle TEXT, numberOfMuscle TEXT);');
}
Future<List<MeasurementsDatabaseModel>> getMeasurementsDatabaseModel() async{
var db_connection = await db;
List<Map> list = await db_connection.rawQuery('SELECT * FROM $TABLE_NAME');
List<MeasurementsDatabaseModel> modelList = new List();
for(int i = 0; i < list.length; i++){
MeasurementsDatabaseModel measurementsDatabaseModel = new MeasurementsDatabaseModel();
measurementsDatabaseModel.id = list[i]['id'];
measurementsDatabaseModel.typeOfMuscle = list[i]['typeOfMuscle'];
measurementsDatabaseModel.numberOfMuscle = list[i]['numberOfMuscle'];
modelList.add(measurementsDatabaseModel);
}
return modelList;
}
void addNewMeasurementsDatabaseModel(MeasurementsDatabaseModel measurementsDatabaseModel) async {
var db_connection = await db;
String query =
'INSERT INTO $TABLE_NAME(name,phone) VALUES( \'${measurementsDatabaseModel.typeOfMuscle}\',\'${measurementsDatabaseModel.numberOfMuscle}\')';
await db_connection.transaction((transition) async{
return await transition.rawInsert(query);
});
}
void updateMeasurementsDatabaseModel(MeasurementsDatabaseModel measurementsDatabaseModel) async {
var db_connection = await db;
String query =
'UPDATE $TABLE_NAME SET name =\'${measurementsDatabaseModel.typeOfMuscle}\',phone =\'${measurementsDatabaseModel.typeOfMuscle}\' WHERE id =${measurementsDatabaseModel.id}';
await db_connection.transaction((transition) async{
return await transition.rawQuery(query);
});
}
void deleteMeasurementsDatabaseModel(MeasurementsDatabaseModel measurementsDatabaseModel) async {
var db_connection = await db;
String query = 'DELETE FROM $TABLE_NAME WHERE id = ${measurementsDatabaseModel.id}';
await db_connection.transaction((transition) async{
return await transition.rawQuery(query);
});
}
}
This is gif, where I want to save data. How can you see, there is container with text near right part of screen. There I want to save data, which I put in AlertDialog.
Firstly, we are going to discuss its simplified implementation. At the MainScreen,
we won't connect it to SQLite. But later on, We can discuss more complex
implementation by calling SQLite queries.
Should we use FutureBuilder ?
In many tutorials spread accross internet, app screen can shows Loading indicator, and later on, it shows ListView and its ListTile after fetching to Database.
It works well if there are no further interaction with ListView later on.
As we using future, the builder will only triggered twice.
class MainScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: queryDatabase(), // Calling Database
builder: (context, snapshot) {
if (snapshot.hasData) { // After Callback, it may triggers this Part
return ListView.builder(
itemBuilder: (_, index) {
return ListTile(
title: Text("$index"),
);
},
);
}
return Center( // First Triggering this Part
child: CircularProgressIndicator(),
);
},
),
);
}
}
The solution is Stateful Widget !
By using Stateful Widget, we can store our products, in variable. Therefore,
each time MainScreen's build method called, the app will display updated List.
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
List<Map<String, dynamic>> products = []; // Store Item, Here
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(...),
body: Container(
child: renderProducts(), // Render stored Item, here
),
);
}
We can see at the demo below, as we interact with buttons, the build method
always being re-called, and fortunately, we can have our Expected Screen
Identified Problems
class _ListItem extends State<ListItem> {
String typeOfMuscle;
String numberOfMuscle;
TextEditingController customcintroller;
...
AlertDialog(
title: Text(name[indexAl]),
content: TextFormField(
controller: customcintroller,
onSaved: (val) => this.numberOfMuscle = val,
),
);
),
the problem is, in onSaved method, the app will only update local variable that
resides on each of ListItem. Therefore, the app does not know that the new value
should be displayed.
How to make the widget rerenders ?
By using setState((){}) as the code below
class _ListItem extends State<ListItem> {
String typeOfMuscle;
String numberOfMuscle;
TextEditingController customcintroller;
...
void updateAndRerender(val){
this.numberOfMuscle = val;
setState((){});
}
AlertDialog(
title: Text(name[indexAl]),
content: TextFormField(
controller: customcintroller,
onSaved: (val) {
updateAndRerender(val);
},
),
);
),
Working Example-App Repo
you may look into this repository. Github
Related
I have a screen which shows list of customers using listview. Next when I click on a customer I want to show the notes(records) only of that particular customer(customerId) in next screen in listview. This is my code which should work fine but its not displaying anything. I have checked if noteDetails table contains data and it has. Can anyone tell where am I wrong or what code should i add more please.
main.dart
import 'package:flutter/material.dart';
import 'package:vers2cts/screens/user_login.dart';
void main() {
runApp(MyApp());
}
Map<int, Color> color ={50:Color.fromRGBO(170, 0, 95, .1),
100:Color.fromRGBO(170, 0, 95, .2),
200:Color.fromRGBO(170, 0, 95, .3),
300:Color.fromRGBO(170, 0, 95, .4),
400:Color.fromRGBO(170, 0, 95, .5),
500:Color.fromRGBO(170, 0, 95, .6),
600:Color.fromRGBO(170, 0, 95, .7),
700:Color.fromRGBO(170, 0, 95, .8),
800:Color.fromRGBO(170, 0, 95, .9),
900:Color.fromRGBO(170,0,95, 1),};
MaterialColor colorCustom = MaterialColor(0xFF880E4F, color);
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'NoteKeeper',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch:colorCustom,
primaryColor:colorCustom//primarySwatch: Colors.purple
),
home: UserLogin(),
);
}
}
Note_info.dart //This is the file where i want to display the notes of particular customer.
import 'dart:io';
import 'package:customer/models/CustomerNote.dart';
import 'package:customer/models/addCustomer.dart';
import 'package:customer/services/db_service.dart';
import 'package:customer/utils/database_helper.dart';
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'New_Note.dart';
class Note_Info extends StatefulWidget{
final String appBarTitle;
final AddCustomer customer;
Note_Info(this. customer, this.appBarTitle);
#override
State<StatefulWidget> createState() {
return Note_InfoState(this. customer,this.appBarTitle);
}
}
class Note_InfoState extends State<Note_Info> {
DBService dbService = DBService();
List<CustomerNote> noteList;
int count = 0;
static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
CustomerNote note=CustomerNote();
String appBarTitle;
AddCustomer customer;
Note_InfoState(this.customer, this.appBarTitle);
DateTime _date = DateTime.now();
TextEditingController custNameController = TextEditingController();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
int customerId=customer.custId;
if (noteList == null) {
noteList = List<CustomerNote>();
updateListView();
}
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
var height = MediaQuery.of(context).size.height;
custNameController.text = customer.custName;
return DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(
Icons.add,
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => NewNote(note)));
},
)
],
),
body: Container(
child: Column(
children: <Widget>[
TextField(controller: custNameController,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(children: [
ImageProfile(customer.custPhoto),
Padding(
padding: const EdgeInsets.only(left: 30.0),
child: IconButton(
icon: Icon(
Icons.call,
color: Colors.green,
size: 45,
),
onPressed: () {
},
),
),
],),
),
SizedBox(
height: 50,
child: AppBar(
bottom: TabBar(
tabs: [
Tab(
text: "All",
),
Tab(
text: "Pending",
),
Tab(
text: "Cancelled",
),
Tab(
text: "Completed",
),
],
),
),
),
// create widgets for each tab bar here
Expanded(
child: TabBarView(
children: [
// first tab bar view widget
Container(
child: getNoteListView()
),
// second tab bar viiew widget
Container(
),
Container(
child: Center(
child: Text(
'Cancelled',
),
),
),
Container(
child: Center(
child: Text(
'Completed',
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 55.0,
width: 200,
child: RaisedButton(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Theme
.of(context)
.primaryColorDark,
textColor: Colors.white,
child: Text('Save', textScaleFactor: 1.5,),
onPressed: () {
setState(() {
//_reset();
});
},
),
),
),
]
),
)
));
}
Widget ImageProfile(String fileName) {
return Center(
child: CircleAvatar(
radius: 80.0,
backgroundImage: fileName == null
?AssetImage('images/person_icon.jpg')
:FileImage(File(customer.custPhoto))),
);
}
ListView getNoteListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
title: Text(this.noteList[position].note, style: titleStyle,),
trailing: GestureDetector(
child: Icon(Icons.delete, color: Colors.grey,),
onTap: () {
},
),
onTap: () {
},
),
);
},
);
}
void updateListView() {
final Future<Database> dbFuture = DB.init();
dbFuture.then((database) {
int cid=customer.custId;
Future<List<CustomerNote>> noteListFuture = dbService.getCustomerNotes(cid);
noteListFuture.then((noteList) {
setState(() {
this.noteList = noteList;
this.count = noteList.length;
});
});
});
}
}
New_Note.dart //This is where new note is added in database successfully
import 'package:customer/models/CustomerNote.dart';
import 'package:customer/models/addCustomer.dart';
import 'package:customer/screens/Note_info.dart';
import 'package:customer/services/db_service.dart';
import 'package:customer/utils/form_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:smooth_star_rating/smooth_star_rating.dart';
import 'package:intl/intl.dart';
class NewNote extends StatefulWidget{
final CustomerNote note;
NewNote(this. note);
final Function(Color) onChanged;
final double height;
final double width;
NewNote({
Key key,
this.onChanged,
this.height = 25,
this.width = 150,
this.label,
}) : super(key: key);*/
#override
State<StatefulWidget> createState() {
return New_NoteState(this.note);
}
}
class New_NoteState extends State<NewNote> with SingleTickerProviderStateMixin{
New_NoteState(this.note);
CustomerNote note=new CustomerNote();
AddCustomer customer=new AddCustomer();
TextEditingController NoteController=TextEditingController();
TextEditingController custNameController = TextEditingController();
DateTime _reminderDate = DateTime.now();
DBService dbService=new DBService();
SpeedDial _speedDial(){
return SpeedDial(
animatedIcon: AnimatedIcons.add_event,
animatedIconTheme: IconThemeData(size: 24.0),
backgroundColor: Colors.yellow,
curve: Curves.easeInCirc,
children: [
SpeedDialChild(
child: Icon(Icons.location_on,color: Colors.yellow,),
label: 'Add Location',
),
SpeedDialChild(
child: Icon(Icons.keyboard_voice),
//backgroundColor: Colors.yellow,
label: 'Add voice',
//labelBackgroundColor: Colors.yellow
),
SpeedDialChild(
child: Icon(Icons.attachment_outlined,color :Colors.redAccent),
label: 'Add File',
),
SpeedDialChild(
child: Icon(Icons.image,color: Colors.lightBlue,),
label: 'Add Image',
),
],
);
}
//for DropDownMenu
Color value=Colors.red;
final List<Color> colors = [
Colors.red,
Colors.blue,
Colors.green,
Colors.yellow,
Colors.pink,
Colors.purple,
Colors.brown,
];
bool isSwitched = false;
var textValue = 'Switch is OFF';
void toggleSwitch(bool value) {
if(isSwitched == false)
{
setState(() {
isSwitched = true;
this.note.remindOn = _reminderDate.toString();
});
}
else
{
setState(() {
isSwitched = false;
});
}
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
custNameController.text = customer.custName;
return WillPopScope(
onWillPop: () {
moveToLastScreen();
},
child: Scaffold(
appBar:AppBar(),
body:ListView(
children: <Widget>[
SizedBox(
height: 2.0,
),
TextField(controller: custNameController,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
Align(
alignment: Alignment.centerLeft,
child: Text("Add New",textAlign: TextAlign.left,
style: TextStyle(fontSize: 22,fontWeight: FontWeight.bold),),
),
SizedBox(
height: 2.0,
),
Divider(),
SizedBox(
height: 2.0,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: NoteController,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: const BorderSide(width: 2.0),)),
keyboardType: TextInputType.multiline,
minLines: 5,
maxLines: 5,
onChanged: (value) {
this.note.note = value;
},
),
),
TableCalendar(
selectedDayPredicate: (day) {
return isSameDay(_reminderDate, day);
},
onDaySelected: (selectedDay, focusedDay) {
setState(() {
_reminderDate = selectedDay;
});
},
focusedDay: DateTime.now(),
firstDay: DateTime.utc(2010, 10, 16),
lastDay: DateTime.utc(2030, 3, 14),),
SizedBox(
height: height*0.03,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(//mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text("Remind me",style: TextStyle(fontSize: 20),),
Padding(
padding: const EdgeInsets.only(left:80.0),
child: Container(
child: Switch(
onChanged: toggleSwitch,
value: isSwitched,
),
),
],),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(mainAxisAlignment: MainAxisAlignment.start,
children:<Widget>[
Text("Priority",style: TextStyle(fontSize: 20.0),),
Padding(
padding: const EdgeInsets.only(left:20.0),
child: Container(
child: SmoothStarRating(
size: height=50.0,
allowHalfRating: false,
onRated: (value) {
this.note.priority=value;
print("rating value -> $value");
},
),
),
)]),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text("Color",style: TextStyle(fontSize: 20),),
Padding(
padding: const EdgeInsets.only(left:80.0),
child: Container(
child: DropdownButton<Color>(
value: value,
onChanged: (color) {
setState(() => value = color);
},
items: colors.map((e) => DropdownMenuItem(
value: e,
child: Container(
width: 60.0,
color: e,
),
),
)
.toList(),
),
),
),
],),
),
SizedBox(
height: height*0.08,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 55.0,
width: 200,
child: RaisedButton(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Theme.of(context).primaryColorDark,
textColor: Colors.white,
child: Text('Save',textScaleFactor: 1.5,),
onPressed: (){
setState(() {
_save();
});
},
),
),
),
],
),
floatingActionButton:_speedDial(),
));
}
void moveToLastScreen() {
Navigator.pop(context, true);
}
void _save() async {
moveToLastScreen();
note.custId=customer.custId;
note.date = DateFormat.yMMMd().format(DateTime.now());
int result;
if (note.id != null) { // Case 1: Update operation
result = await dbService.updateNote(note);
} else { // Case 2: Insert Operation
result = await dbService.insertNote(note);
}
if (result != 0) { // Success
FormHelper.showAlertDialog(context,'Status', 'Note Saved Successfully');
} else { // Failure
FormHelper.showAlertDialog(context,'Status', 'Problem Saving Note');
}
}
}
db_service.dart
Future<bool> insertCustomer(AddCustomer model) async {
await DB.init();
bool isSaved = false;
if (model != null) {
int inserted = await DB.insert(AddCustomer.table, model);
isSaved = inserted == 1 ? true : false;
}
return isSaved;
}
Future<List<Map<String, dynamic>>> getCustomerMapList() async {
await DB.init();
var result = await DB.query(AddCustomer.table);
return result;
}
Future<List<AddCustomer>> getCustomerList() async {
var CustomerMapList = await getCustomerMapList();
int count = CustomerMapList.length;
List<AddCustomer> customerList = List<AddCustomer>();
for (int i = 0; i < count; i++) {
customerList.add(AddCustomer.fromMap(CustomerMapList[i]));
}
return customerList;
}
Future<int> insertNote(CustomerNote note) async {
await DB.init();
var result = await DB.insert(CustomerNote.table, note);
return result;
}
Future<List<CustomerNote>> getCustomerNotes(int customer) async {
await DB.init();
var res = await DB.rawQuery("noteDetails WHERE custId = '$customer'");
int count = res.length;
List<CustomerNote> notelist = List<CustomerNote>();
for (int i = 0; i < count; i++) {
notelist.add(CustomerNote.fromMap(res[i]));
}
return notelist;
}
database_helper.dart
import 'dart:async';
import 'package:customer/models/model.dart';
import 'package:path/path.dart' as p;
import 'package:sqflite/sqflite.dart';
abstract class DB {
static Database _db;
static int get _version => 1;
static Future<Database> init() async {
if (_db != null) {
return _db;
}
try {
var databasesPath = await getDatabasesPath();
String _path = p.join(databasesPath, 'Customer.db');
_db = await openDatabase(_path, version: _version, onCreate: onCreate);
print('db location:'+_path);
} catch (ex) {
print(ex);
}
}
static void onCreate(Database db, int version) async {
await db.execute(
'CREATE TABLE userDetails (id INTEGER PRIMARY KEY AUTOINCREMENT, '
'firstName STRING, '
'lastName STRING, mobileNum STRING, emailId STRING, address String,'
'userType STRING,password STRING)');
await db.execute(
'CREATE TABLE customerDetails (custId INTEGER PRIMARY KEY AUTOINCREMENT, '
'custName STRING, '
'mobileNum STRING, company STRING, custPhoto STRING, showOnCall bool,'
'remindOn STRING,location STRING)');
await db.execute(
'CREATE TABLE noteDetails (noteId INTEGER PRIMARY KEY AUTOINCREMENT, '
'custId STRING, '
'custName STRING, date STRING, note STRING, remindOn STRING,'
'priority STRING,status STRING,attachment STRING)');
await db.execute(
'CREATE TABLE languagesKnown(custId INTEGER REFERENCES customerDetails(custId),'
' languages STRING,PRIMARY KEY(custId))');
}
static Future<List<Map<String, dynamic>>> query(String table) async =>
_db.query(table);
static Future<int> insert(String table, Model model) async =>
await _db.insert(table, model.toMap());
static Future<int> update(String table, Model model) async => await _db
.update(table, model.toMap(), where: 'id = ?', whereArgs: [model.id]);
static Future<int> delete(String table, Model model) async =>
await _db.delete(table, where: 'id = ?', whereArgs: [model.id]);
static Future<int> deleteCustomer(String table, Model model) async =>
await _db.delete(table, where: 'custId = ?', whereArgs: [model.custId]);
static Future<Batch> batch() async => _db.batch();
static Future<List<Map<String, dynamic>>> rawQuery(String table) async =>
_db.query(table);
}
people_list.dart // This is where list of customers is displayed and by clicking on a listtile i.e customer, Note_info opens
import 'package:customer/models/addCustomer.dart';
import 'package:customer/screens/Note_info.dart';
import 'package:customer/screens/User_Settings.dart';
import 'package:customer/screens/add_person.dart';
import 'package:customer/services/db_service.dart';
import 'package:customer/utils/database_helper.dart';
import 'package:customer/utils/form_helper.dart';
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:sqflite/sqflite.dart';
class People_List extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return People_ListState();
}
}
class People_ListState extends State<People_List> with SingleTickerProviderStateMixin{
DBService dbService = DBService();
List<AddCustomer> customerList;
int count = 0;
static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
var _isSelectedItemIndex;
#override
void initState() {
super.initState();
_searchQuery = new TextEditingController();
}
Widget _buildTitle(BuildContext context) {
var horizontalTitleAlignment =
Platform.isIOS ? CrossAxisAlignment.center : CrossAxisAlignment.start;
return new InkWell(
onTap: () => scaffoldKey.currentState.openDrawer(),
child: new Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: horizontalTitleAlignment,
children: <Widget>[
const Text(''),
],
),
),
);
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
if (customerList == null) {
customerList = List<AddCustomer>();
updateListView();
}
return Scaffold(
appBar: new AppBar(
),
body:getCustomerListView(),
floatingActionButton: FloatingActionButton(
onPressed: () {
navigateToCustomer(AddCustomer(), 'Add Person');
},
child: const Icon(Icons.add),
),
}
ListView getCustomerListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
var _imageFile=customerList[position].custPhoto;
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
leading: CircleAvatar(
backgroundImage: _imageFile==null?AssetImage('images/person_icon.jpg')
:FileImage(File(_imageFile.toString()))),
title: Text(this.customerList[position].custName, style: titleStyle,),
trailing: Icon(Icons.keyboard_arrow_right),
onTap: () {
navigateToDetail(this.customerList[position],'Edit ');
},
),
);
},
);
}
void navigateToDetail(AddCustomer customer, String title) async {
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) {
return Note_Info(customer, title);
}));
if (result == true) {
updateListView();
}
}
void updateListView() {
final Future<Database> dbFuture = DB.init();
dbFuture.then((database) {
Future<List<AddCustomer>> customerListFuture = dbService.getCustomerList();
customerListFuture.then((customerList) {
setState(() {
this.customerList = customerList;
this.count = customerList.length;
});
});
});
}
}
Finally I myself had to solve the problem. The problem was that where I was creating note and saving it in "note" table cust_id was not saved in the table. So I passed CustomerModel object and NoteModel object to New_Note(). Now its working fine
new_note.dart
class NewNote extends StatefulWidget{
final NoteModel note;
final CustomerModel customer;
NewNote(this.customer,this. note);
#override
State<StatefulWidget> createState() {
//return New_NoteState(this.customer);
return New_NoteState(this.customer,this.note);
}
class New_NoteState extends State<NewNote> with SingleTickerProviderStateMixin{
New_NoteState(this.customer,this.note);
NoteModel note=new NoteModel();
CustomerModel customer=new CustomerModel();
}
void _save() async {
note.cust_id=customer.cust_id;
...
}
I am using a FutureBuilder to display data from a sqlite database. I can add data to that database using a drawer that is also on that page. When I add new data I want the FutureBuilder to automatically update so the page will display the new data that was just added to the sqlite database. How could I properly go about doing this? Thanks!
The page where the data is displayed using the FutureBuilder
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[200],
appBar: PreferredSize(
preferredSize: Size.fromHeight(95.0),
child: AppBar(
automaticallyImplyLeading: false, // hides leading widget
flexibleSpace: DataAppBar(),
),
),
body: FutureBuilder<dynamic>(
future: DataDBProvider.dataDB.getData(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
print(
'${snapshot.error}',
);
}
}
List data = snapshot.data;
return ListView.builder(
itemCount: data.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 1.0, horizontal: 4.0),
child: Card(
color: (index % 2 == 0) ? greycolor : Colors.white,
child: Container(
height: 60,
padding: EdgeInsets.fromLTRB(0, 20, 0, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Flexible(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(left: 4),
child: Text(data[index].date,
style: TextStyle(fontSize: 14),
textAlign: TextAlign.left),
),
],
),
),
Expanded(
flex: 5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(data[index].title,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
color: Colors.black,
fontFamily: 'Montserrat'),
textAlign: TextAlign.center)
],
)),
],
),),
Expanded(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text('\$${data[index].amount}',
style: TextStyle(fontSize: 17,
color: Colors.black),
textAlign: TextAlign.right),
],
),
),
],
)),
),
);
},
);
}
));
}
You can copy paste run full code below
To achieve automatically update so the page will display the new data
In this case, you can use package https://pub.dev/packages/sqlbrite and StreamBuilder
sqlbrite is Streaming sqflite, The BriteDatabase.createQuery method is similar to Database.query. Listen to the returned Stream<Query> which will immediately notify with a Query to run.
And the page will automatically display the new data
code snippet
class AppDb {
...
final _dbFuture = _open().then((db) => BriteDatabase(db));
Stream<List<Item>> getAllItems() async* {
final db = await _dbFuture;
yield* db
.createQuery(_tableItems, orderBy: 'createdAt DESC')
.mapToList((json) => Item.fromJson(json));
}
Future<bool> insert(Item item) async {
final db = await _dbFuture;
final id = await db.insert(
_tableItems,
item.toJson(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
return id != -1;
}
Future<bool> remove(Item item) async {
...
}
Future<bool> update(Item item) async {
...
}
}
...
StreamBuilder<List<Item>>(
stream: AppDb.getInstance().getAllItems(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
final items = snapshot.data;
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
working demo
full code
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:sqlbrite/sqlbrite.dart';
import 'dart:math';
const _tableItems = 'items';
Future<Database> _open() async {
final directory = await getApplicationDocumentsDirectory();
final path = join(directory.path, 'example.db');
return await openDatabase(
path,
version: 1,
onCreate: (Database db, int version) async {
await db.execute(
'''
CREATE TABLE $_tableItems(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
content TEXT NOT NULL,
createdAt TEXT NOT NULL
)
''',
);
final batch = db.batch();
for (int i = 0; i < 10; i++) {
batch.insert(
_tableItems,
Item(
null,
contents.random(),
DateTime.now(),
).toJson(),
);
}
final list = await batch.commit(
continueOnError: true,
noResult: false,
);
print('Batch result: $list');
},
);
}
class AppDb {
static AppDb _singleton;
AppDb._();
factory AppDb.getInstance() => _singleton ??= AppDb._();
final _dbFuture = _open().then((db) => BriteDatabase(db));
Stream<List<Item>> getAllItems() async* {
final db = await _dbFuture;
yield* db
.createQuery(_tableItems, orderBy: 'createdAt DESC')
.mapToList((json) => Item.fromJson(json));
}
Future<bool> insert(Item item) async {
final db = await _dbFuture;
final id = await db.insert(
_tableItems,
item.toJson(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
return id != -1;
}
Future<bool> remove(Item item) async {
final db = await _dbFuture;
final rows = await db.delete(
_tableItems,
where: 'id = ?',
whereArgs: [item.id],
);
return rows > 0;
}
Future<bool> update(Item item) async {
final db = await _dbFuture;
final rows = await db.update(
_tableItems,
item.toJson(),
where: 'id = ?',
whereArgs: [item.id],
conflictAlgorithm: ConflictAlgorithm.replace,
);
return rows > 0;
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData.dark(),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
final _dateFormatter = DateFormat.Hms().add_yMMMd();
MyHomePage({Key key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('sqlbrite example'),
),
body: Container(
constraints: BoxConstraints.expand(),
child: StreamBuilder<List<Item>>(
stream: AppDb.getInstance().getAllItems(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
final items = snapshot.data;
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return ListTile(
title: Text(item.content),
subtitle:
Text('Created: ${_dateFormatter.format(item.createdAt)}'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(Icons.remove_circle),
onPressed: () => _remove(item),
),
IconButton(
icon: Icon(Icons.edit),
onPressed: () => _update(item),
),
],
),
);
},
);
},
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: _add,
),
);
}
void _add() async {
final item = Item(
null,
contents.random(),
DateTime.now(),
);
final success = await AppDb.getInstance().insert(item);
print('Add: $success');
}
void _remove(Item item) async {
final success = await AppDb.getInstance().remove(item);
print('Remove: $success');
}
void _update(Item item) async {
final success = await AppDb.getInstance().update(
item.copyWith(
contents.random(),
),
);
print('Update: $success');
}
}
const contents = [
'Aaren',
'Aarika',
'Abagael',
'Abagail',
'Abbe',
'Abbey',
'Abbi',
'Abbie',
'Abby',
'Abbye',
'Abigael',
'Abigail',
'Abigale',
'Abra',
'Ada',
'Adah',
'Adaline',
'Adan',
'Adara',
'Adda',
'Addi',
'Addia',
'Addie',
'Addy',
'Adel',
'Adela',
'Adelaida',
'Adelaide',
'Adele',
'Adelheid',
'Adelice',
'Adelina',
'Adelind',
'Adeline',
'Adella',
'Adelle',
'Adena',
'Adey',
'Adi',
'Adiana',
'Adina',
'Adora',
'Adore',
'Adoree',
'Adorne',
'Adrea',
'Adria',
'Adriaens',
'Adrian',
'Adriana',
'Adriane',
'Adrianna',
'Adrianne',
'Adriena',
'Adrienne',
'Aeriel',
'Aeriela',
'Aeriell',
'Afton',
'Ag',
'Agace',
'Agata',
'Agatha',
'Agathe',
'Aggi',
'Aggie',
'Aggy',
'Agna',
'Agnella',
'Agnes',
'Agnes',
];
extension RandomElementExtension<T> on List<T> {
T random() {
final index = Random().nextInt(length);
return this[index];
}
}
class Item {
final int id;
final String content;
final DateTime createdAt;
const Item(
this.id,
this.content,
this.createdAt,
);
factory Item.fromJson(Map<String, dynamic> json) {
return Item(
json['id'],
json['content'],
DateTime.parse(json['createdAt']),
);
}
Map<String, dynamic> toJson() {
return {
if (id != null) 'id': id,
'content': content,
'createdAt': createdAt.toIso8601String(),
};
}
Item copyWith(String content) => Item(id, content, createdAt);
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Item &&
runtimeType == other.runtimeType &&
id == other.id &&
content == other.content &&
createdAt == other.createdAt;
#override
int get hashCode => id.hashCode ^ content.hashCode ^ createdAt.hashCode;
#override
String toString() =>
'Item{id: $id, content: $content, createdAt: $createdAt}';
}
I am creating a flutter application which will store Image-url inside cloud firestore database and that url get fetched in the form of image and display inside my flutter application. The problem is with image-url sometime it is get saved inside the database and sometime it does not. When it get saved the fetching process work properly and when it does not saved or unsaved it will reture a error value with null msg which is shown in the image.
I don't know why this is happening sometime the data get saved and sometime it is unsaved.
Pls see the below code for saving of Image inside the cloud firestore database.
import 'package:intl/intl.dart';
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mi_card/duplicate.dart';
import 'package:image_picker/image_picker.dart';
import 'package:mi_card/widget/provider_widget.dart';
import 'package:path/path.dart' as path;
import 'package:firebase_storage/firebase_storage.dart';
import '../sec.dart';
class EditProductScreen extends StatefulWidget {
#override
_EditProductScreenState createState() => _EditProductScreenState();
}
class _EditProductScreenState extends State<EditProductScreen> {
//for selecting picture from galary of phone
var sampleImage;
Future captureImage() async {
var tempImage = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
sampleImage = tempImage;
});
String fileName = path.basename(sampleImage.path);
final StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child('entry/student entry/'+fileName);
final StorageUploadTask task =
firebaseStorageRef.putFile(sampleImage);
var ImageUrl= await(await task.onComplete).ref.getDownloadURL();
url=ImageUrl.toString();
print("Image Url="+url);
//saveToDatabase(url);
}
void saveToDatabase(url){
}
//for camera opening and capturing the picture
Future getImage() async {
var tempImage = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
sampleImage = tempImage;
});
String fileName = path.basename(sampleImage.path);
final StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child('entry/student entry/'+fileName);
final StorageUploadTask task =
firebaseStorageRef.putFile(sampleImage);
var ImageUrl= await(await task.onComplete).ref.getDownloadURL();
url=ImageUrl.toString();
print("Image Url="+url);
saveToDatabase(url);
}
final _priceFocusNode = FocusNode();
final _formKey = GlobalKey<FormState>();
final _firestore = Firestore.instance;
String url;
var _initValues = {
'title': '',
'description': '',
'price': '',
'imageUrl': '',
};
var _isInit = true;
#override
void didChangeDependencies() {
if (_isInit) {
final productId = ModalRoute.of(context).settings.arguments as String;
}
_isInit = false;
super.didChangeDependencies();
}
#override
void dispose() {
_priceFocusNode.dispose();
super.dispose();
}
void _saveForm() async{
final isValid = _formKey.currentState.validate();
if (!isValid) {
return;
}
_formKey.currentState.save();
var dbTimeKey = new DateTime.now();
var formatDate=new DateFormat('dd/MMMM/yyyy');
var formatTime=new DateFormat('dd/MMMM/yyyy &'' hh:mm aaa, EEEE');
String date = formatDate.format(dbTimeKey);
String time = formatTime.format(dbTimeKey);
final uid = await Provider.of(context).auth.getCurrentUID();
// collection reference for every user
DocumentReference Collection = Firestore.instance.collection(' entry').document();
Collection.setData({
"Entry-time": time,
'image': url,
});
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyApp()),
);
}
List<String> _locations = ['NA','1st year', '2 year', '3 year', '4 year']; // Option 2
String _selectedLocation;
#override
Widget build(BuildContext context) {
var _blankFocusNode = new FocusNode();
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text('ENTRY'),
centerTitle: true,
leading: new
IconButton(
icon: Icon(Icons.arrow_back),
color: Colors.white,
onPressed: () {
Navigator.pop(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
},
),
actions: <Widget>[
FlatButton(
textColor: Colors.white,
onPressed: _saveForm,
child: Text("Save",),
),
],
),
backgroundColor: Colors.blueAccent,
body: GestureDetector (
onTap: () {
FocusScope.of(context).requestFocus(_blankFocusNode);
},
child: Form(
key: _formKey,
child: ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
SizedBox(
height: 20.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Align(
alignment: Alignment.center,
child: CircleAvatar(
radius:73 ,
backgroundColor: Colors.white,
child: ClipOval(
child: new SizedBox(
width: 125,
height:125,
child: sampleImage != null
? Image.file(
sampleImage,
height: 108,
fit: BoxFit.fill,
)
: IconButton(
icon: Icon(
Icons.person,
color: Colors.grey[400],
),
iconSize: 80.0,
//onPressed:_takePicture
),
),
),
),
),
Padding(
padding: EdgeInsets.only(top: 0.0),
child: IconButton(
icon: Icon(
Icons.camera_alt,
color: Colors.black,
size: 30.0,
),
onPressed: captureImage,
),
),
Padding(
padding: EdgeInsets.only(top: 00.0),
child: IconButton(
icon: Icon(
Icons.folder,
color: Colors.orangeAccent[100],
size: 30.0,
),
onPressed: getImage,
),
),
],
),
],
),
),
),
);
}
}
How to handle this error ?
Here is a better approach to uploading images to storage and getting url back
final StorageReference storageReference =
FirebaseStorage().ref().child("path/$name");
final StorageUploadTask uploadTask =
storageReference.putFile(imaeFile);
final StreamSubscription<StorageTaskEvent> streamSubscription =
uploadTask.events.listen((event) {
// You can use this to notify yourself or your user in any kind of way.
// For example: you could use the uploadTask.events stream in a StreamBuilder instead
// to show your user what the current status is. In that case, you would not need to cancel any
// subscription as StreamBuilder handles this automatically.
print('EVENT ${event.type}');
});
// Cancel your subscription when done.
await uploadTask.onComplete;
streamSubscription.cancel();
String url =
await (await uploadTask.onComplete).ref.getDownloadURL();
saveToDatabase(url);
I started learning Flutter. I am developing a simple application using it. Now, I am developing a feature where my application will display the records from the SQLite database and where the user adds the new records into the SQLite database. But my ListView is displaying the blank screen.
I have a class called DatabaseHelper with the following code.
class DatabaseHelper {
static DatabaseHelper _databaseHelper;
Database _database;
String noteTable = 'note_table';
String colId = 'id';
String colTitle = 'title';
String colDescription = 'description';
String colPriority = 'priority';
String colDate = 'date';
DatabaseHelper._createInstance();
factory DatabaseHelper() {
if (_databaseHelper == null) {
_databaseHelper = DatabaseHelper._createInstance();
}
return _databaseHelper;
}
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'notes.db';
var notesDatabase = await openDatabase(path, version: 1, onCreate: _createDB);
return notesDatabase;
}
void _createDB(Database db, int newVersion) async {
await db.execute('CREATE TABLE $noteTable($colId INTEGER PRIMARY KEY AUTOINCREMENT, $colTitle TEXT, $colDescription TEXT, $colPriority INTEGER, $colDate TEXT)');
}
Future<List<Map<String, dynamic>>> getNoteMapList() async {
Database db = await this.database;
return await db.query(noteTable, orderBy: '$colPriority ASC');
}
Future<int> insertNote(Note note) async {
Database db = await this.database;
return await db.insert(noteTable, note.toMap());
}
Future<int> updateNote(Note note) async {
var db = await this.database;
return await db.update(noteTable, note.toMap(), where: '$colId = ?', whereArgs: [note.id]);
}
Future<int> deleteNote(int id) async {
var db = await this.database;
return await db.rawDelete('DELETE FROM $noteTable WHERE $colId = $id');
}
Future<int> getCount() async {
Database db = await this.database;
List<Map<String, dynamic>> x = await db.rawQuery('SELECT COUNT(*) FROM $noteTable');
return Sqflite.firstIntValue(x);
}
}
Then I have a widget called NoteList with the following code where the list of items are displayed.
class NoteList extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _NoteListState();
}
}
class _NoteListState extends State<NoteList> {
List<Note> _notes = [];
int _count = 0;
DatabaseHelper _databaseHelper = DatabaseHelper();
_NoteListState() {
this._notes = getNotes();
this._count = _notes.length;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Notes"),),
body: Container(
child: getListView(context),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
navigateToNoteForm("Add Note");
},
),
);
}
Widget getListView(BuildContext context) {
return ListView.builder(
itemCount: _count,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: _notes[index].priority == 1? Colors.yellow: Colors.red,
child: Icon(_notes[index].priority == 1 ? Icons.arrow_right : Icons.add),
),
title: Text(_notes[index].title),
subtitle: Text(_notes[index].date),
trailing: Icon(Icons.delete),
onTap: () {
navigateToNoteForm("Edit Note", _notes[index]);
},
);
});
}
void navigateToNoteForm(String pageTitle, [Note note]) async {
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) {
return NoteForm(pageTitle, note);
}));
if (result) {
setState(() {
debugPrint("Updating list");
_notes = getNotes();
_count = _notes.length;
});
}
}
List<Note> getNotes() {
List<Note> notes = List<Note>();
Future<List<Map<String, dynamic>>> notesFuture = _databaseHelper.getNoteMapList();
notesFuture.then((notesMap) {
debugPrint("Total notes found in the database ${notesMap.length}");
notesMap.forEach((map) {
notes.add(Note.fromMapObject(map));
});
});
return notes;
}
}
Then I also have another widget class called NoteForm with the following code.
class NoteForm extends StatefulWidget {
String _title = "";
Note _note = null;
NoteForm(String title, [Note note]) {
this._title = title;
this._note = note;
}
#override
State<StatefulWidget> createState() {
return _NoteFormState();
}
}
class _NoteFormState extends State<NoteForm> {
double _minimumPadding = 15.0;
var _priorities = [ 1, 2 ];
var _titleController = TextEditingController();
var _descriptionController = TextEditingController();
var _dateController = TextEditingController();
DatabaseHelper _databaseHelper = DatabaseHelper();
var _selectedPriority = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget._title),),
body: Builder(
builder: (scaffoldContext) => Form(
child: Column(
children: <Widget>[
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: TextFormField(
controller: _titleController,
decoration: InputDecoration(
labelText: "Title",
hintText: "Enter title"
),
),
),
),
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: TextFormField(
controller: _descriptionController,
decoration: InputDecoration(
labelText: "Description",
hintText: "Enter description"
),
),
)
),
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: TextFormField(
controller: _dateController,
decoration: InputDecoration(
labelText: "Date",
hintText: "Enter date"
),
),
),
),
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: DropdownButton<int>(
value: _selectedPriority,
items: _priorities.map((dropdownItem) {
return DropdownMenuItem<int>(
value: dropdownItem,
child: Text(dropdownItem == 1? "Low": "High"),
);
}).toList(),
onChanged: (int newSelectedValue) {
setState(() {
_selectedPriority = newSelectedValue;
});
},
),
),
),
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: RaisedButton(
child: Text(
"Save"
),
onPressed: () {
_save(scaffoldContext);
},
),
),
)
],
),
),
)
);
}
void _save(BuildContext context) async {
Note note = Note();
note.title = _titleController.text;
note.description = _descriptionController.text;
note.date = _dateController.text;
note.priority = _selectedPriority;
if (widget._note != null && widget._note.id!=null) {
//update
_databaseHelper.updateNote(note);
this.showSnackBar(context, "Note has been updated.");
} else {
//create
_databaseHelper.insertNote(note);
this.showSnackBar(context, "Note has been added.");
}
closeForm(context);
}
void showSnackBar(BuildContext context, String message) {
var snackBar = SnackBar(
content: Text(message),
action: SnackBarAction(
label: "UNDO",
onPressed: () {
},
),
);
Scaffold.of(context).showSnackBar(snackBar);
}
void closeForm(BuildContext context) {
Navigator.pop(context, true);
}
}
When I run my application, it is just displaying the blank screen as follows.
As you can see I am logging out the number of records returned from the database using debugPrint method. It is saying that there are 6 records within the database. It is just not displaying the records. What is wrong with my code and how can I fix it?
As i mention in comment that was happening because of async task take some time to perform and if you do not keep it async then setState function execute before actual data load or set.
So Following changes solve your issue.
make getNotes async method And
getNotes().then((noteresponce){ setState((){ _notes=noteresponce; _count = _notes.length;} });
How can i save photo to firebase storage and send the url link to cloud firestore ??
I am using image picker to pick the Image my code is shown below ....
import 'package:flutter/material.dart';
import 'package:onlinecity/component/TextField/inputField.dart';
import 'package:onlinecity/component/Button/roundedButton.dart';
import 'package:onlinecity/component/Button/textButton.dart';
import 'style.dart';
import 'package:onlinecity/theme/style.dart';
import 'package:flutter/services.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';
import 'dart:async';
class AddOfferScreen extends StatefulWidget {
#override
AddOfferScreenState createState() => new AddOfferScreenState();
}
class AddOfferScreenState extends State<AddOfferScreen> {
final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
bool _autovalidate = false;
String _productTitle;
String _category;
String _contactNumber;
FirebaseStorage storage;
String _path;
File _cachedFile;
Future<File> _imageFile;
void _onImageButtonPressed(ImageSource source) {
setState(() {
_imageFile = ImagePicker.pickImage(source: source);
});
}
_onPressed() {
print("button clicked");
}
void showInSnackBar(String value) {
_scaffoldKey.currentState
.showSnackBar(new SnackBar(content: new Text(value)));
}
bool _handleSubmitted() {
final FormState form = _formKey.currentState;
if (form.validate()) {
form.save();
return true;
}
return false;
}
void validateAndSubmit() async{
if (_handleSubmitted()){
try {
Firestore.instance.collection('todos').document().setData({"productTitle":_productTitle,"category":_category,"contactNumber":_contactNumber});
}
catch (e){
print('Error: $e');
}
}
}
void _showaddphoto(){
AlertDialog dialog = new AlertDialog(
actions: <Widget>[
new IconButton(icon: new Icon(Icons.camera_alt), onPressed: () => _onImageButtonPressed(ImageSource.camera),
tooltip: 'Take a Photo'),
new IconButton(icon: new Icon(Icons.sd_storage), onPressed: () => _onImageButtonPressed(ImageSource.gallery),
tooltip: 'Pick Image from gallery')
],
);
showDialog(context: context,child: dialog);
}
#override
Widget build(BuildContext context) {
// TODO: implement build
Size screenSize = MediaQuery.of(context).size;
//print(context.widget.toString());
return new Scaffold(
key: _scaffoldKey,
body: new SingleChildScrollView(
child: new Container(
padding: new EdgeInsets.all(16.0),
decoration: new BoxDecoration(image: backgroundImage),
child: new Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new SizedBox(
height: screenSize.height / 2 + 20,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
"CREATE ACCOUNT",
textAlign: TextAlign.center,
style: headingStyle,
)
],
)),
new Column(
children: <Widget>[
new Form(
key: _formKey,
autovalidate: _autovalidate,
//onWillPop: _warnUserAboutInvalidData,
child: new Column(
children: <Widget>[
new FutureBuilder<File>(
future: _imageFile,
builder: (BuildContext context, AsyncSnapshot<File> snapshot){
if (snapshot.connectionState == ConnectionState.done &&
snapshot.data != null) {
return new Image.file(snapshot.data);
} else if (snapshot.error != null) {
return const Text('error picking image.');
} else {
return const Text(
'You have not yet picked an image.');
}
},
),
new RaisedButton.icon(onPressed: _showaddphoto, icon: new Icon(Icons.add_a_photo), label: new Text('Add Photo')),
new InputField(
hintText: "product title",
obscureText: false,
textInputType: TextInputType.text,
textStyle: textStyle,
textFieldColor: textFieldColor,
icon: Icons.person_outline,
iconColor: Colors.white,
bottomMargin: 20.0,
validateFunction: (value)=> value.isEmpty ? 'UserName can\'t be empty' : null,
onSaved: (value)=> _productTitle = value,
),
new InputField(
hintText: "Category",
obscureText: false,
textInputType: TextInputType.emailAddress,
textStyle: textStyle,
textFieldColor: textFieldColor,
icon: Icons.mail_outline,
iconColor: Colors.white,
bottomMargin: 20.0,
validateFunction: (value)=> value.isEmpty ? 'Email can\'t be empty' : null,
onSaved: (value)=> _category = value,
),
new InputField(
hintText: "Contact Number",
obscureText: true,
textInputType: TextInputType.text,
textStyle: textStyle,
textFieldColor: textFieldColor,
icon: Icons.lock_open,
iconColor: Colors.white,
bottomMargin: 40.0,
validateFunction: (value)=> value.isEmpty ? 'Contact number can\'t be empty' : null,
onSaved: (value)=> _contactNumber = value,
),
new RoundedButton(
buttonName: "Continue",
onTap: validateAndSubmit,
width: screenSize.width,
height: 50.0,
bottomMargin: 10.0,
borderWidth: 1.0)
],
)),
new TextButton(
buttonName: "Terms & Condition", onPressed: _onPressed,buttonTextStyle: buttonTextStyle,)
],
)
],
),
),
));
}
}
Here is a code snippet. You should run this when you have File from ImagePicker.
Image picker: Notice that setState cannot be async, so you need to await outside and in setState pass local variable to the field.
void _onImageButtonPressed(ImageSource source) async {
File image = await ImagePicker.pickImage(source: source);
setState(() {
_imageFile = image;
});
}
This snippet you need to call when you want to upload
var fileName = "fileName.jpeg";
StorageUploadTask putFile =
storage.ref().child("folder/$fileName").putFile(_image);
putFile.future.catchError(onError);
UploadTaskSnapshot uploadSnapshot = await putFile.future;
print("image uploaded");
Map<String, dynamic> pictureData = new Map<String, dynamic>();
pictureData["url"] = uploadSnapshot.downloadUrl.toString();
DocumentReference collectionReference =
Firestore.instance.collection("collection").document(fileName);
await Firestore.instance.runTransaction((transaction) async {
await transaction.set(collectionReference, pictureData);
print("instance created");
}).catchError(onError);