Im new to flutter and first time to work with sqlite database.
I have created a todo app that is linked to a Sqlite database. It has simple cards that i can add and it works fine. The problem is, I have a delete icon, but for some reason the cards do not delete when I press the delete icon. I get the following error message in the stack:
E/SQLiteLog(22653): (1) no such table: çustomerblueprint in "DELETE FROM çustomerblueprint WHERE id == ?"
E/flutter (22653): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: DatabaseException(no such table: çustomerblueprint (code 1 SQLITE_ERROR[1]): , while compiling: DELETE FROM çustomerblueprint WHERE id == ?) sql 'DELETE FROM çustomerblueprint WHERE id == ?' args [1]
I have read for hours to try and fine a solution, but don't seem to get this one.
My code is:
Database Code
class CustomerBluePrint {
int? id;
final String title;
DateTime creationDate;
bool isChecked;
CustomerBluePrint({
this.id,
required this.title,
required this.creationDate,
required this.isChecked,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'title': title,
'creationDate': creationDate.toString(),
'isChecked': isChecked ? 1 : 0,
};
}
#override
String toString() {
return 'CustomerBluePrint(id : $id, title : $title, creationDate : $creationDate, isChecked
: $isChecked )'; // , phone : $phone, mobile : $mobile, fax : $fax, email : $email, name :
$name)';
}
}
class DatabaseConnect {
Database? _database;
Future<Database> get database async {
final dbpath = await getDatabasesPath();
const dbname = 'customerblueprint.db';
final path = join(dbpath, dbname);
_database = await openDatabase(path, version: 1, onCreate: _createDB);
return _database!;
}
Future<void> _createDB(Database db, int version) async {
await db.execute('''
CREATE TABLE todo(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
creationDate TEXT,
isChecked INTEGER
)
''');
}
Future<void> insertCustomerBluePrint(
CustomerBluePrint customerblueprint) async {
final db = await database;
await db.insert(
'customerblueprint',
customerblueprint.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
Future<void> deleteCustomerBluePrint(
CustomerBluePrint customerblueprint) async {
final db = await database;
await db.delete(
'çustomerblueprint',
where: 'id == ?',
whereArgs: [customerblueprint.id],
);
}
Future<List<CustomerBluePrint>> getCustomerBluePrint() async {
final db = await database;
List<Map<String, dynamic>> items = await db.query(
'customerblueprint',
orderBy: 'id DESC',
);
return List.generate(
items.length,
(i) => CustomerBluePrint(
id: items[i]['id'],
title: items[i]['title'],
creationDate: DateTime.parse(items[i]['creationDate']),
isChecked: items[i]['isChecked'] == 1 ? true : false,
),
);
}
}
Customer List Code
import 'package:flutter/material.dart';
import 'library.dart';
import 'customer_card.dart';
class CustomerList extends StatelessWidget {
final Function insertFunction;
final Function deleteFunction;
final db = DatabaseConnect();
CustomerList(
{required this.insertFunction, required this.deleteFunction, Key? key})
: super(key: key);
#override
Widget build(BuildContext context) {
return Expanded(
child: FutureBuilder(
future: db.getCustomerBluePrint(),
initialData: const [],
builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
var data = snapshot.data;
var datalength = data!.length;
return datalength == 0
? const Center(
child: Text('no data found'),
)
: ListView.builder(
itemCount: datalength,
itemBuilder: (context, i) => CustomerCard(
id: data[i].id,
title: data[i].title,
creationDate: data[i].creationDate,
isChecked: data[i].isChecked,
insertFunction: insertFunction,
deleteFunction: deleteFunction,
),
);
},
),
);
}
}
Customer Card Code
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'library.dart';
class CustomerCard extends StatefulWidget {
final int id;
final String title;
final DateTime creationDate;
bool isChecked;
final Function insertFunction;
final Function deleteFunction;
CustomerCard(
{required this.id,
required this.title,
required this.creationDate,
required this.isChecked,
required this.insertFunction,
required this.deleteFunction,
Key? key})
: super(key: key);
#override
_CustomerCardState createState() => _CustomerCardState();
}
class _CustomerCardState extends State<CustomerCard> {
#override
Widget build(BuildContext context) {
var anotherCustomerBluePrint = CustomerBluePrint(
id: widget.id,
title: widget.title,
creationDate: widget.creationDate,
isChecked: widget.isChecked);
return Card(
child: Row(
children: [
Container(
margin: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
child: Checkbox(
value: widget.isChecked,
onChanged: (bool? value) {
setState(() {
widget.isChecked = value!;
});
anotherCustomerBluePrint.isChecked = value!;
widget.insertFunction(anotherCustomerBluePrint);
},
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.title,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
const SizedBox(height: 5),
Text(
DateFormat('dd MMM yyyy - hh:mm aaa')
.format(widget.creationDate),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Color(0xFF8F8F8F),
),
)
],
),
),
IconButton(
onPressed: () {
widget.deleteFunction(anotherCustomerBluePrint);
},
icon: const Icon(Icons.close),
),
],
),
);
}
}
Customer Code
This is my Homepage
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:invoice_app/customer_profile.dart';
import 'customer_list.dart';
import 'library.dart';
class Customer extends StatefulWidget {
const Customer({Key? key}) : super(key: key);
#override
_CustomerState createState() => _CustomerState();
}
class _CustomerState extends State<Customer> {
var db = DatabaseConnect();
void addItem(CustomerBluePrint customerblueprint) async {
await db.insertCustomerBluePrint(customerblueprint);
setState(() {});
}
void deleteItem(CustomerBluePrint customerblueprint) async {
await db.deleteCustomerBluePrint(customerblueprint);
setState(() {
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5EBFF),
body: Column(
children: [
CustomerList(
insertFunction: addItem, deleteFunction: deleteItem),
CustomerProfile(
insertFunction: addItem
),
],
),
);
}
The deletefunction is suppose to delete an entry based on the 'id'assigned to it. Everything works fine, except I cannot delete a card (entry) as it throws the error.
Please help. Would really appreciate it.
Found your mistake take a look at Database Code and implementation of the method Future<void> deleteCustomerBluePrint(CustomerBluePrint customerblueprint) You have an error there. Your:
await db.delete(
'çustomerblueprint',
where: 'id == ?',
whereArgs: [customerblueprint.id],
);
Mine Repaired:
await db.delete(
'customerblueprint',
where: 'id == ?',
whereArgs: [customerblueprint.id],
);
An error in the word customerblueprint, you do not have the letter "c" there, you have some other sign.
Related
I'm using Flutter, I need to save image in SQLite as BLOB, then display it in my page.
I did it as String and it works fine but not image with 1.5 MB size, the app get unhanded exception, I tried to do it as blob but I could not find any tutorial anywhere.
My model:
import 'package:flutter/services.dart';
const String tablePersonal = 'personal_info';
class PersonalFields {
static final List<String> values = [
id,
name,
logo,
];
static const String id = '_id';
static const String name = 'name';
static const String logo = 'logo';
}
class PersonalInfoModel {
int? id;
final String name;
final Uint8List? logo;
PersonalInfoModel({
this.id,
required this.name,
this.logo,
});
PersonalInfoModel copy({
int? id,
String? name,
Uint8List? logo,
}) =>
PersonalInfoModel(
id: id ?? this.id,
name: name ?? this.name,
logo: logo ?? this.logo,
);
static PersonalInfoModel fromJson(Map<String, Object?> json) =>
PersonalInfoModel(
id: json[PersonalFields.id] as int?,
name: json[PersonalFields.name] as String,
logo: json[PersonalFields.logo] as Uint8List?,
);
Map<String, dynamic> toJson() => {
PersonalFields.id: id,
PersonalFields.name: name,
PersonalFields.logo: logo,
};
}
SQL Helper: after create the table I just make insert null record to save the id = 1 so that I will just update the record. That is means the table will only get one record.
batch.execute('''
CREATE TABLE IF NOT EXISTS $tablePersonal
(
${PersonalFields.id} $idType,
${PersonalFields.name} $textType,
${PersonalFields.logo} $blobType
)
''');
batch.execute('''
INSERT INTO $tablePersonal
(
${PersonalFields.name}
)
VALUES
(
''
)
''');
//read personal info
Future<List<PersonalInfoModel>> getPesonalInfo() async {
var db = await instanace.database;
final result = await db.query(tablePersonal);
return result.map((json) => PersonalInfoModel.fromJson(json)).toList();
}
Future<int> updatePersonalInfo(PersonalInfoModel personalInfoModel) async {
final db = await instanace.database;
return db.update(
tablePersonal,
personalInfoModel.toJson(),
where: '${PersonalFields.id} = ?',
whereArgs: [personalInfoModel.id],
);
}
My Page:
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:ledger/database/sql_helper.dart';
import 'package:ledger/l10n/app_local.dart';
import 'package:ledger/models/personal_info_model.dart';
class PersonalInfoPage extends StatefulWidget {
const PersonalInfoPage({Key? key}) : super(key: key);
#override
State<PersonalInfoPage> createState() => _PersonalInfoPageState();
}
class _PersonalInfoPageState extends State<PersonalInfoPage> {
final _formKey = GlobalKey<FormState>();
final TextEditingController _nameController = TextEditingController();
double boxWidth = 10;
double boxHieght = 10;
XFile? xImage;
var bytes;
final ImagePicker _picker = ImagePicker();
late List<PersonalInfoModel> personalList;
late PersonalInfoModel existPersonal;
bool isLoading = true;
#override
void initState() {
super.initState();
getPersonalInfo();
}
Future pickImage() async {
try {
xImage = await _picker.pickImage(source: ImageSource.gallery);
if (xImage == null) return;
final imagePath = File(xImage!.path);
bytes = imagePath;
setState(() {});
} on PlatformException catch (e) {
print('Failed to pick image: $e');
}
}
Future getPersonalInfo() async {
final data = await SQLHelper.instanace.getPesonalInfo();
setState(() {
personalList = data;
getData();
isLoading = false;
});
}
getData() {
existPersonal = personalList.firstWhere((element) => element.id == 1);
_nameController.text = existPersonal.name;
bytes = existPersonal.logo;
}
Future updatePersonalInfo(PersonalInfoModel personalInfoModel) async {
await SQLHelper.instanace.updatePersonalInfo(personalInfoModel);
getPersonalInfo();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocal.loc.personal_info),
actions: [
IconButton(
onPressed: () {
PersonalInfoModel personalInfoModel = PersonalInfoModel(
id: 1,
name: _nameController.text,
logo: bytes);
updatePersonalInfo(personalInfoModel);
},
icon: const Icon(Icons.save_as_outlined),
),
],
),
body: isLoading
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0),
child: Form(
key: _formKey,
child: Column(
children: [
SizedBox(height: boxHieght),
TextFormField(
controller: _nameController,
decoration: InputDecoration(
filled: true,
labelText: AppLocal.loc.name,
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0),
),
),
),
),
],
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () {
print('xxxxxx');
pickImage();
},
child: Text('from Gallary'),
),
],
),
Container(
color: Colors.grey.shade100,
height: 150,
width: 150,
child: bytes != null
? Image.memory(bytes)
: Image.asset('assets/logo.png'),
),
],
),
),
);
}
}
Here is how you can convert it into a blob and save it to SQLite
Future pickImage(ImageSource source) async {
try {
final image = await ImagePicker.pickImage(source: source);
final imagePath = File(image.path);
List<int> bytes = await image.readAsBytes();
String base64 = base64Encode(bytes);// here it is. Save it to sqflite
} on PlatformException catch (e) {
print(e);
}
}
for getting from SQLite
String blobImageFromSqflite; //get from sqflite
Uint8List _bytesImage = Base64Decoder().convert(blobImageFromSqflite);
to display it;
Image.memory(
_bytesImage,
);
I used Share_Prefereces library so I want to save date of adding Item. I tried many ways but
I always get the errors: E/flutter ( 2786): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'Null' is not a subtype of type 'DateTime'
and the second error is: Unhandled Exception: Converting object to an encodable object failed: Instance of 'Shopping'
so please help me
the code of Date file is:
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Shopping {
String item;
int price;
DateTime date;
Shopping({required this.item, required this.price, required this.date});
Map<String, dynamic> toJson() {
return {
'item': item,
'price': price,
'date': date,
};
}
}
class ItemData extends ChangeNotifier {
List<Shopping> listOfItem = [];
void addItem(Shopping shopping) {
listOfItem.add(shopping);
notifyListeners();
}
void editItem(Shopping shopping, int itemIndex) {
listOfItem[itemIndex] = shopping;
notifyListeners();
}
void deleteItem(int itemIndex) {
listOfItem.removeAt(itemIndex);
notifyListeners();
}
saveData() async {
SharedPreferences pref = await SharedPreferences.getInstance();
List<String> tempList = [];
for (int i = 0; i < listOfItem.length; i++) {
tempList.add(jsonEncode(listOfItem[i]));
}
pref.remove("itemList");
pref.setStringList("itemList", tempList);
}
loadData() async {
SharedPreferences pref = await SharedPreferences.getInstance();
if (pref.getStringList('itemList') != null) {
List<String> tempList = pref.getStringList('itemList')!;
for (int i = 0; i < tempList.length; i++) {
Map<String, dynamic> temp = jsonDecode(tempList[i]);
addItem(
Shopping(
item: temp['item'],
price: temp['price'],
date: temp['date'],
),
);
}
}
}
}
and the code of adding Item, price and date is:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:goods_and_price/shopping_data.dart';
import 'package:provider/provider.dart';
class AddItem extends StatelessWidget {
AddItem({Key? key}) : super(key: key);
TextEditingController userInputItem = TextEditingController();
TextEditingController userInputPrice = TextEditingController();
#override
Widget build(BuildContext context) {
var provider = Provider.of<ItemData>(context, listen: true);
DateTime date = DateTime.now();
return Scaffold(
appBar: AppBar(
title: const Text('Add Item'),
centerTitle: true,
backgroundColor: const Color(0xFF00899C),
),
body: ListView(
physics: const BouncingScrollPhysics(),
children: [
Padding(
padding: const EdgeInsets.all(10.0),
child: TextField(
controller: userInputItem,
decoration: InputDecoration(
hintText: 'Item',
labelText: 'Item',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
prefixIcon: const Icon(
Icons.shopping_cart,
color: Color(0xFF00899C),
)),
maxLines: null,
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: TextField(
controller: userInputPrice,
decoration: InputDecoration(
hintText: 'Price',
labelText: 'Price',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
prefixIcon: const Icon(
Icons.attach_money,
color: Color(0xFF00899C),
)),
maxLines: null,
),
),
const SizedBox(
height: 10,
),
CupertinoButton(
padding: const EdgeInsets.all(0),
pressedOpacity: 0.5,
child: Container(
height: 50,
width: 120,
decoration: BoxDecoration(
color: const Color(0xFF00899C),
borderRadius: BorderRadius.circular(10)),
child: const Center(
child: Text(
'Add Item',
style: TextStyle(color: Colors.white),
),
),
),
onPressed: () async {
Shopping newItem = Shopping(
item: userInputItem.text,
price: int.parse(userInputPrice.text),
date: date,
);
provider.addItem(newItem);
provider.saveData();
Navigator.pop(context);
},
),
],
),
);
}
}
I don't recommend using DateTime, because it takes a certain amount of work to use in different languages, I find it easier to use String.
I couldn't simulate the error on my machine, but I made an example, I hope it helps.
To create class I like to use this site https://javiercbk.github.io/json_to_dart/
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:zoociadoleite_app/global/my_app.dart';
class TesteScreen extends StatefulWidget {
const TesteScreen({Key key}) : super(key: key);
#override
State<TesteScreen> createState() => _TesteScreenState();
}
class Shopping {
String item;
int price;
String date;
Shopping({this.item, this.price, this.date});
Shopping.fromJson(Map<String, dynamic> json) {
item = json['item'];
price = json['price'];
date = json['date'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['item'] = this.item;
data['price'] = this.price;
data['date'] = this.date;
return data;
}
}
class LocalStorage {
Future<String> get(String item) async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString(item);
}
Future<bool> set(String item, dynamic data) async {
final prefs = await SharedPreferences.getInstance();
return prefs.setString(item, json.encode(data));
}
Future<bool> remove(String item) async {
final prefs = await SharedPreferences.getInstance();
return prefs.remove(item);
}
}
class _TesteScreenState extends State<TesteScreen> {
final formatDate = new DateFormat.yMMMMd('pt_BR');
Future<List<Shopping>> _future;
List<Shopping> list = [];
load() async {
String data = await LocalStorage().get("Shopping");
if (data != null) {
List<dynamic> lista = json.decode(data) as List;
list = lista.map((shopping) => Shopping.fromJson(shopping)).toList();
}
_future = Future.value(list);
setState(() {});
}
#override
void initState() {
super.initState();
load();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Shopping>>(
future: _future,
builder: (context, snapshot) {
if (snapshot.hasData)
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
Shopping shopping = snapshot.data[index];
return ListTile(
title: Text(shopping.item),
subtitle: Text("${shopping.price}"),
trailing: Text("${formatDate.format(DateTime.parse(shopping.date))}"),
);
},
);
return CircularProgressIndicator();
},
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
list.add(Shopping(item: "test_${list.length + 1}", price: list.length + 1, date: DateTime.now().toString()));
_future = Future.value(list);
LocalStorage().set("Shopping", list);
setState(() {});
},
child: const Icon(Icons.add),
),
);
}
}
I am trying to retrieve and display a list of items on firebase, I have been able to access everything else on firebase apart from the list itself. I think the issue might be how I am going about retrieving the list because of the method in which it was saved. Here is the order model code
import 'package:butcherbox/models/productsModel.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:meta/meta.dart';
class Order {
Order(
{#required this.items,
//this.theItems,
this.location,
this.orderId,
this.time,
#required this.price});
final List<ProductsModel> items;
final String location;
final int orderId;
final Timestamp time;
final int price;
factory Order.fromMap(Map<String, dynamic> data) {
if (data == null) {
return null;
}
final List<ProductsModel> items = data['items'];
final String location = data['location'];
final int price = data['price'];
final int orderId = data['orderId'];
final Timestamp time = data['time'];
return Order(
items: items,
location: location,
price: price,
orderId: orderId,
time: time,
);
}
Map<String, dynamic> toMap() {
return {
'item': items.map((e) => e.toJson()).toList(),
'location': location,
'orderId': orderId,
'time': time,
'price': price
};
}
}
This is the code to display the data
import 'package:butcherbox/butch_widgets/order_list_tile.dart';
import 'package:butcherbox/models/ordersmodel.dart';
import 'package:butcherbox/services/database.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class Orders extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.green[200],
title: Text(
'Orders',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.green[900]),
),
),
body: _buildContents(context),
);
}
Widget _buildContents(BuildContext context) {
final database = Provider.of<Database>(context, listen: false);
return StreamBuilder<List<Order>>(
stream: database.ordersStream(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final orders = snapshot.data;
// final children =
// orders.map((order) => Text(order.location)).toList();
final children =
orders.map((order) => OrderListTile(order: order)).toList();
return ListView(children: children);
}
if (snapshot.hasError) {
return Center(child: Text('Some Error Occurred'));
}
return Center(child: CircularProgressIndicator());
});
}
}
This is the widget for the UI
import 'package:butcherbox/models/ordersmodel.dart';
import 'package:flutter/material.dart';
class OrderListTile extends StatelessWidget {
final Order order;
const OrderListTile({Key key, #required this.order}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListTile(
title: Text(
'Order No: ${order.orderId}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.green[900]),
),
trailing: Text(
'Vendor: ${order.location}',
style: TextStyle(fontSize: 16),
),
subtitle: ListView.builder(
itemCount: order.items.length, <-- This is where the error is
shrinkWrap: true,
itemBuilder: (context, i) {
return Expanded(
child: Column(
children: [
Text('${order.items[i].name}'),
Text('${order.items[i].quantity.toString()}')
],
),
);
}),
isThreeLine: true,
);
}
}
This is the database code
import 'package:butcherbox/models/ordersmodel.dart';
import 'package:butcherbox/services/api_path.dart';
import 'package:meta/meta.dart';
import 'package:butcherbox/services/firestore_service.dart';
abstract class Database {
Future<void> createOrder(Order order);
Stream<List<Order>> ordersStream();
}
String docFromId() => DateTime.now().toIso8601String();
class FireStoreDatabase implements Database {
FireStoreDatabase({#required this.uid}) : assert(uid != null);
final String uid;
final _service = FireStoreService.instance;
Future<void> createOrder(Order order) => _service.setData(
//path: APIPath.order(uid, 'orderdetails'), data: order.toMap());
path: APIPath.order(uid, docFromId()),
data: order.toMap(),
);
Stream<List<Order>> ordersStream() => _service.collectionStream(
path: APIPath.orders(uid), builder: (data) => Order.fromMap(data));
}
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/foundation.dart';
class FireStoreService {
FireStoreService._();
static final instance = FireStoreService._();
Future<void> setData({String path, Map<String, dynamic> data}) async {
final reference = FirebaseFirestore.instance.doc(path);
print('$path: $data');
await reference.set(data);
}
Stream<List<T>> collectionStream<T>({
#required String path,
#required T Function(Map<String, dynamic> data) builder,
}) {
final reference = FirebaseFirestore.instance.collection(path);
final snapshots = reference.snapshots();
return snapshots.map((snapshot) => snapshot.docs
.map(
(snapshot) => builder(snapshot.data()),
)
.toList());
}
}
Yes actually you are right, so here are some keypoints,
Stream<List<Order>> ordersStream() => _service.collectionStream(
path: APIPath.orders(uid), builder: (data) =>
// This is supposed to be a list of Orders.
Order.fromMap(data));
You can try printing the data here so you see what I am talking about(it would be a List and not a singular object).
I am receiving a null values when I am calling the getItems() method in database_client.dart file (retrieving all items name) ...so basically I am dealing with just two functions here which are saveItem() and getItems(). But itemName is storing in db as null value and i don't know why it is getting it as a null value ... there is no error in my code but the problem is that null values I am receiving of _itemName_and _dateCreated fields which are present in nodo_item.dart file.
I am going to give you my whole project code so that you can easily find out the problem here.
main.dart
import 'package:flutter/material.dart';
import 'package:no_to_do_app/ui/home.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
title: 'NotoDo',
home: new Home(),
);
}
}
home.dart
import 'package:flutter/material.dart';
import 'package:no_to_do_app/ui/notodo_screen.dart';
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: Text('NoToDo'),
backgroundColor: Colors.black54,
),
body: new NoToDoScreen(
)
);
}
}
nodo_item.dart
import 'package:flutter/material.dart';
class NoDoItem extends StatelessWidget {
late String? _itemName;
late String? _dateCreated;
int? _id;
NoDoItem( this._itemName , this._dateCreated, {Key? key}) : super(key: key);
NoDoItem.map(dynamic obj, {Key? key}) : super(key: key)
{
_itemName = obj['ItemName'];
_dateCreated = obj['DateCreated'];
_id = obj['id'];
}
String? get itemName => _itemName;
String? get dateCreated => _dateCreated;
int? get id => _id;
Map<String , dynamic>toMap()
{
var map = <String , dynamic>{};
map['ItemName'] = _itemName;
map['DateCreated'] = _dateCreated;
/*if(_id !=null)
{
map['id'] = _id;
}*/
map['id'] = _id;
return map;
}
NoDoItem.fromMap(Map<String , dynamic>map, {Key? key}) : super(key: key)
{
_itemName = map['ItemName'];
_dateCreated = map['DateCreated'];
_id = map['id'];
}
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(_itemName! ,
style: const TextStyle(
color: Colors.white,
fontSize: 16.5,
fontWeight: FontWeight.bold
),),
Container(
margin: const EdgeInsets.only(top: 5.0),
child: Text('Created on: $_dateCreated',
style: const TextStyle(
color: Colors.white70,
fontStyle: FontStyle.italic,
fontSize: 13.4
),),
)
],
)
);
}
}
database_client.dart
import 'dart:async';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:no_to_do_app/model/nodo_item.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseHelper
{
static final DatabaseHelper _instance = DatabaseHelper.private();
DatabaseHelper.private();
factory DatabaseHelper() => _instance;
final String tableName = "nodoTbl";
final String columnId = "id";
final String columnItemName = "itemName";
final String columnDateCreated = "dateCreated";
static late Database _db;
Future<Database> get database async
{
/*if(_db!=null)
{
return _db;
}*/
_db =await initDb();
return _db;
}
DatabaseHelper.internal();
initDb() async
{
Directory documentDirectory = await getApplicationDocumentsDirectory();
String path = join(documentDirectory.path, "notodo_db.db");
var ourDb= await openDatabase(path , version: 1 , onCreate: _onCreate);
return ourDb;
}
void _onCreate(Database db, int version) async
{
await db.execute(
"CREATE TABLE $tableName(id INTEGER PRIMARY KEY , $columnItemName TEXT ,$columnDateCreated TEXT)"
);
debugPrint('Table is Created');
}
Future<int> saveItem(NoDoItem item) async
{
var dbClient = await database;
int res =await dbClient.insert(tableName, item.toMap());
debugPrint(res.toString());
return res;
}
Future<List> getItems() async
{
var dbClient = await database;
var result = await dbClient.rawQuery("SELECT * FROM $tableName ORDER BY $columnItemName ASC");
return result.toList();
}
Future<int?> getCount() async
{
var dbClient = await database;
return Sqflite.firstIntValue(await dbClient.rawQuery(
"SELECT COUNT(*) FROM $tableName"
));
}
Future<NoDoItem?> getItem(int id) async{
var dbClient = await database;
var result = await dbClient.rawQuery("SELECT * FROM $tableName WHERE id=$id");
//if(result.length==0) return null;
if(result.isEmpty) return null;
return NoDoItem.fromMap(result.first);
}
Future<int> deleteItem(int id) async
{
var dbClient =await database;
return await dbClient.delete(tableName,where: "$columnId = ?", whereArgs: [id]);
}
Future<int> updateItem(NoDoItem item) async
{
var dbClient =await database;
return await dbClient.update(tableName, item.toMap(),
where: "$columnId=?", whereArgs: [item.id]);
}
Future close() async
{
var dbClient =await database;
return dbClient.close();
}
}
notodo_screen.dart
import 'package:flutter/material.dart';
import 'package:no_to_do_app/model/nodo_item.dart';
import 'package:no_to_do_app/util/database_client.dart';
class NoToDoScreen extends StatefulWidget {
const NoToDoScreen({Key? key}) : super(key: key);
#override
_NoToDoScreenState createState() => _NoToDoScreenState();
}
class _NoToDoScreenState extends State<NoToDoScreen> {
final TextEditingController _textEditingController = TextEditingController();
var db = DatabaseHelper();
#override
void initState() {
// TODO: implement initState
super.initState();
_readNotoDoItems();
}
void _hndleSubmitted(String text) async
{
_textEditingController.clear();
NoDoItem noDoItem = NoDoItem(text, DateTime.now().toIso8601String());
int savedItemId = await db.saveItem(noDoItem);
debugPrint("Item saved ID: $savedItemId");
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black87,
body: Column(),
floatingActionButton: FloatingActionButton(
tooltip: 'Add Item',
backgroundColor: Colors.redAccent,
child: const ListTile(
title: Icon(Icons.add)
),
onPressed: _showFormDialog),
);
}
void _showFormDialog() {
var alert = AlertDialog(
content: Row(
children: [
Expanded(
child: TextField(
controller: _textEditingController,
autofocus: true,
decoration: const InputDecoration(
labelText: 'item',
hintText: "eg. Don't buy Stuff",
icon: Icon(Icons.add_circle_outline_outlined)
),
))
],
),
actions: [
TextButton(
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all<Color>(Colors.blue),
),
onPressed: () {
_hndleSubmitted(_textEditingController.text);
_textEditingController.clear();
},
child: const Text("Save"),
),
TextButton(
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all<Color>(Colors.blue),
),
onPressed: () => Navigator.pop(context),
child: const Text("Cancel"),)
]
);
showDialog(context: context,
builder: (_) {
return alert;
});
}
_readNotoDoItems() async
{
List items = await db.getItems();
items.forEach((item) {
NoDoItem noDoItem = NoDoItem.map(item);
print("Db items: ${noDoItem.itemName}");
});
}
}
Output I am getting after running the project:
Performing hot restart...
Syncing files to device Android SDK built for x86...
Restarted application in 8,386ms.
I/flutter ( 3831): Db items: null
I/flutter ( 3831): Db items: null
I/flutter ( 3831): Db items: null
I/flutter ( 3831): Db items: null
I/flutter ( 3831): Db items: null
I/flutter ( 3831): Db items: null
I/flutter ( 3831): Db items: null
I/flutter ( 3831): Db items: null
I/flutter ( 3831): Db items: null
I/flutter ( 3831): Db items: null
I/flutter ( 3831): Db items: null
D/InputConnectionAdaptor( 3831): The input method toggled cursor monitoring on
I/TextInputPlugin( 3831): Composing region changed by the framework. Restarting the input method.
W/IInputConnectionWrapper( 3831): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper( 3831): getTextBeforeCursor on inactive InputConnection
D/InputConnectionAdaptor( 3831): The input method toggled cursor monitoring on
I/flutter ( 3831): 12
I/flutter ( 3831): Item saved ID: 12
This is my first month as coder. I am trying to develop nearby places app. When i used following codes im getting error of "null check operator used on a null value". But based on what i see or when i printed url and checked manually or when i used if condition i see no problem or no error. Just when i rendered screen im getting this error. I would like to ask if someone can point me what is wrong ? Thanks in advance!
The line im getting error is locationName: locationSuggestion!.query.pages[0]!.title. Probibly and following locationSuggestion class.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_udemy_examples/http_api_data/get_location_data_final.dart';
import 'package:flutter_udemy_examples/http_api_data/get_location_names.dart';
import 'package:flutter_udemy_examples/screens/login_ekrani.dart';
import 'package:flutter_udemy_examples/screens/map_screen.dart';
import 'login_ekrani.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../banner.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_udemy_examples/http_api_data/get_location_images.dart';
// ignore: must_be_immutable
class HomeScreen extends StatefulWidget {
#override
State<HomeScreen> createState() => HomeScreenState();
}
class HomeScreenState extends State<HomeScreen> {
LocationDataFinal? locationSuggestion;
bool isLoading = true;
#override
void initState() {
super.initState();
asyncInitState();
}
Future<void> asyncInitState() async {
await fecthlocationData();
}
Future fecthlocationData() async {
var locations = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
final double enlem = locations.latitude;
final double boylam = locations.longitude;
final url = Uri.parse(
"https://en.wikipedia.org/w/api.php?action=query&format=json&prop=coordinates%7Cpageimages%7Cdescription%7Cextracts&generator=geosearch&piprop=original&descprefersource=central&exlimit=20&exintro=1&explaintext=1&exsectionformat=plain&ggscoord=${enlem}%7C${boylam}&ggsradius=10000");
print(url);
final response = await http.get(url);
//print(response.body);
if (response.statusCode == 200) {
locationSuggestion = await locationDataFinalFromJson(response.body);
if (locationSuggestion != null) {
setState(() {
isLoading = false;
});
} else {
print("null1");
}
} else {
print("null2");
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: _buildAppBar(context),
body: isLoading
? Center(
child: CircularProgressIndicator(),
)
: ListView(
children: [
MyBanner(
// info: locationSuggestion!.query.pages[0]!.description,
locationName: locationSuggestion!.query.pages[0]!.title,
imagePath:
locationSuggestion!.query.pages[0]!.original.source,
context: context,
),
MyBanner(
//info: locationSuggestion!.query.pages[1]!.description,
locationName: locationSuggestion!.query.pages[1]!.title,
imagePath:
locationSuggestion!.query.pages[1]!.original.source,
context: context,
),
MyBanner(
// info: locationSuggestion!.query.pages[2]!.description,
locationName: locationSuggestion!.query.pages[2]!.title,
imagePath:
locationSuggestion!.query.pages[2]!.original.source,
context: context,
),
MyBanner(
// info: locationSuggestion!.query.pages[3]!.description,
locationName: locationSuggestion!.query.pages[3]!.title,
imagePath:
locationSuggestion!.query.pages[3]!.original.source,
context: context,
),
MyBanner(
// info: locationSuggestion!.query.pages[4]!.description,
locationName: locationSuggestion!.query.pages[4]!.title,
imagePath:
locationSuggestion!.query.pages[4]!.original.source,
context: context,
),
],
),
);
}
AppBar _buildAppBar(BuildContext context) {
return AppBar(
automaticallyImplyLeading: false,
leading: RotatedBox(
quarterTurns: 2,
child: _buildExitButton(context),
),
actions: [
_buildOpenMapButton(),
_buildCallEmergencyNumberButton(),
],
titleSpacing: 25,
shadowColor: Colors.white,
elevation: 0.0,
backgroundColor: Colors.blue[800],
//titleSpacing: Padding(padding: EdgeInsets.fromLTRB(25.85.0, 0, 25.85.0, 0)),
title: Text("Traveler Doctor"),
);
}
Widget _buildCallEmergencyNumberButton() {
return IconButton(
disabledColor: Colors.red,
color: Colors.red,
icon: Icon(Icons.phone_enabled),
tooltip: "Local emergency number",
onPressed: null,
);
}
Widget _buildOpenMapButton() {
return IconButton(
disabledColor: Colors.orangeAccent,
color: Colors.limeAccent,
icon: Icon(Icons.map_rounded),
tooltip: "Map",
enableFeedback: false,
onPressed: () => {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) => MapScreen()))
},
);
}
}
Widget _buildExitButton(BuildContext context) {
return IconButton(
onPressed: () async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('KullaniciAdi', "");
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (BuildContext context) => LoginEkrani()));
},
icon: Icon(
Icons.exit_to_app,
color: Colors.red,
),
tooltip: "Exit",
);
}
And this is the model im using for parsing api response
import 'dart:convert';
LocationDataFinal locationDataFinalFromJson(String str) =>
LocationDataFinal.fromJson(json.decode(str));
class LocationDataFinal {
LocationDataFinal({
required this.batchcomplete,
required this.query,
});
String batchcomplete;
Query query;
factory LocationDataFinal.fromJson(Map<String, dynamic> json) =>
LocationDataFinal(
batchcomplete: json["batchcomplete"],
query: Query.fromJson(json["query"]),
);
}
class Query {
Query({
required this.pages,
});
Map<String, Page> pages;
factory Query.fromJson(Map<String, dynamic> json) => Query(
pages: Map.from(json["pages"])
.map((k, v) => MapEntry<String, Page>(k, Page.fromJson(v))),
);
}
class Page {
Page({
required this.pageid,
required this.ns,
required this.title,
required this.index,
required this.coordinates,
required this.original,
required this.description,
required this.descriptionsource,
required this.extract,
});
int pageid;
int ns;
String title;
int index;
List<Coordinate> coordinates;
Original original;
String description;
String descriptionsource;
String extract;
factory Page.fromJson(Map<String, dynamic> json) => Page(
pageid: json["pageid"],
ns: json["ns"],
title: json["title"],
index: json["index"],
coordinates: List<Coordinate>.from(
json["coordinates"].map((x) => Coordinate.fromJson(x))),
original: json["original"] == null
? Original(
source:
"https://tigres.com.tr/wp-content/uploads/2016/11/orionthemes-placeholder-image-1.png",
width: 300,
height: 200)
: Original.fromJson(json["original"]),
description: json["description"] == null ? "asd" : json["description"],
descriptionsource:
json["descriptionsource"] == null ? " " : json["descriptionsource"],
extract: json["extract"],
);
}
class Coordinate {
Coordinate({
required this.lat,
required this.lon,
required this.primary,
required this.globe,
});
double lat;
double lon;
String primary;
Globe globe;
factory Coordinate.fromJson(Map<String, dynamic> json) => Coordinate(
lat: json["lat"].toDouble(),
lon: json["lon"].toDouble(),
primary: json["primary"],
globe: globeValues.map[json["globe"]]!,
);
}
enum Globe { EARTH }
final globeValues = EnumValues({"earth": Globe.EARTH});
class Original {
Original({
required this.source,
required this.width,
required this.height,
});
String source;
int width;
int height;
factory Original.fromJson(Map<String, dynamic> json) => Original(
source: json["source"],
width: json["width"],
height: json["height"],
);
}
class EnumValues<T> {
late Map<String, T> map;
late Map<T, String> reverseMap;
EnumValues(this.map);
}
I will be checking this post frequently.
Thanks in advance again.
Sincerely ur noob coder.
Would leave this as a comment but apparently I only have enough reputation to write answers.
In your Query object pages is a Map<String, Page> but you're accessing it with a int key: locationSuggestion!.query.pages[0]!.title
To access the map with an int key, it needs to be Map<int,Page> (or List<Page>)
Somewhat i solved issue by replacing
locationSuggestion!.query.pages[0]!.titlewith
locationSuggestion!.query.pages.values.elementAt(0).title
This way of adressing solved issue for me :)