load data using provider call while navigating to the screen - flutter

I have managed to load data from odoo db, the data can be loaded at first call but after updating or creatinig a new customer in server side odoo database nothing happens in my flutter app. the data not loaded in customer screen
i tried to call the provider in initState , setState but nothing worked for me.
customer model
class Customer {
int id;
String name;
Customer({
required this.id,
required this.name,
});
factory Customer.fromJson(Map<dynamic, dynamic> json) => Customer(
name: json["name"],
id: json["id"],
);
Map<dynamic, dynamic> toJson() => {
"name": name,
"id": id,
};
}
Customer provider
class CustomerProvider with ChangeNotifier {
CustomerProvider() {
loadCustomers().then((customers) {
_customers = customers;
notifyListeners();
});
}
List<Customer> _customers = [];
List<Customer> get customers => _customers;
Future getCustomer() async {
notifyListeners();
final client = OdooClient('http://localhost:8050');
await client.authenticate('odoo', 'admin', 'admin');
var res = await client.callKw({
'model': 'res.partner',
'method': 'search_read',
'args': [],
'kwargs': {
'context': {'bin_size': true},
// 'domain': [
// ['id','=',10]
// ],
'fields': ['name'],
},
});
return res;
}
Future loadCustomers() async {
notifyListeners();
final data = await getCustomer();
_customers = ((data as List).map((i) => Customer.fromJson(i)).toList());
return _customers;
}
}
Customer screen
class CustomerPage extends StatefulWidget {
final bool? isMultiSelection;
final List<Customer> customers;
const CustomerPage({
Key? key,
this.isMultiSelection = false,
this.customers = const [],
}) : super(key: key);
#override
_CustomerPageState createState() => _CustomerPageState();
}
class _CustomerPageState extends State<CustomerPage> {
String text = '';
bool loading = false;
List<Customer>? csm;
#override
void initState() {
super.initState();
}
bool containsSearchText(Customer customer) {
final name = customer.name;
final textLower = text.toLowerCase();
final customerLower = name.toLowerCase();
return customerLower.contains(textLower);
}
#override
Widget build(BuildContext context) {
var provider = Provider.of<CustomerProvider>(context, listen: false);
var allcustomers = provider.customers;
var customers = allcustomers.where(containsSearchText).toList();
return ChangeNotifierProvider.value(
value: CustomerProvider(),
child: loading ? const Loading() : Scaffold(
appBar: AppBar(
title: const Text('Selectionner un client'),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(60),
child: SearchWidget(
text:text,
hintText: 'Rechercher',
onChanged: (text) => setState(() => this.text = text),
)),
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: <Color>[Color(0xffC71C24), Color(0xffFDBA45)]),
),
),
),
body: customers.isEmpty
// ? const Center(child: CircularProgressIndicator(color: Color(0xffFDBA45),),)
? const Loading()
: ListView(
children: customers.map((customer) {
return CustomerListTileWidget(
customer: customer,
isSelected: false,
onSelectedCustomer: selectCustomer
);
}).toList(),
),
)
);
}

Related

How to save image as blob in sqlite in flutter

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,
);

How do I resolve a Sqlite Error (1) in Flutter?

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.

Flutter display server data / response from json

I have built a page which reads the json from recipeURL and I wish for it to display the product_name value in the json file. However for some reason my future fetchData () class isn't being read as none of the text in my if else statement is being displayed. Am I missing a simple oversight here?
EDIT: The main dart file is my main screen. This is where my navbar is created. Users are redirected to other pages when they click on the corresponding icon. Im having trouble passing BarcodePage(title:title); as parameters in my main file,26th line, can be found under Class MyAppState extends State<MyApp> {
My main dart file:
import 'package:flutter/material.dart';
import 'pages/BarcodePage.dart';
import 'pages/FoodPage.dart';
import 'pages/RecipePage.dart';
import 'pages/ShoppingPage.dart';
void main() {
runApp(MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState(){
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
int _selectedPage =0;
final _pageOptions= [
FoodPage(),
RecipePage(),
BarcodePage(title: ,),
ShoppingPage(),
];
#override
Widget build(BuildContext context) {
return MaterialApp(
//title: 'Best B4',
theme: ThemeData(
primarySwatch: Colors.teal,),
debugShowCheckedModeBanner: false,
home: Scaffold (
appBar: AppBar(
title:Text(
'BestB4',
style: TextStyle(
fontFamily: 'PacificoRegular',
fontSize: 30,
),
),
backgroundColor: Colors.teal,
elevation: 20,
actions: [
IconButton(
icon: Icon(Icons.qr_code_2_rounded),
tooltip: 'Add item',
onPressed:(){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => BarcodePage()));
},
)
],
//ONPRESSED MENU OPEN
),
body:_pageOptions[_selectedPage],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.teal,
selectedItemColor: Colors.white,
unselectedItemColor: Colors.white70,
iconSize: 40,
selectedFontSize: 15,
unselectedFontSize: 15,
currentIndex:_selectedPage,
onTap: (int index) {
setState(() {
_selectedPage = index;
});
},
items: [
BottomNavigationBarItem(
icon:Icon(Icons.restaurant_rounded),
label: 'Food',
), //, title:Text('Food')
BottomNavigationBarItem(
icon:Icon(Icons.menu_book_rounded),
label:'Recipes',
),//, title:Text('Recipes')
BottomNavigationBarItem(
icon:Icon(Icons.add_outlined),
label:'Add',
),//, title:Text('Add')
BottomNavigationBarItem(
icon:Icon(Icons.shopping_cart_rounded),
label:'Shopping',
),//,title:Text('Shopping')
],
),
),
);
}
}
My BarcodePage dart file:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as p;
import 'package:flutter/services.dart';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:http/http.dart';
class BarcodePage extends StatefulWidget{
const BarcodePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_BarcodePageState createState() => _BarcodePageState();
}
var futuredata = {};
class _BarcodePageState extends State<BarcodePage> {
int counter=0;
String result= "";
Future _scanBarcode() async{
try{
ScanResult scanResult = await BarcodeScanner.scan();
String barcodeResult = scanResult.rawContent;
setState(() {
result = barcodeResult;
});
} on PlatformException catch (ex) {
if (ex.code == BarcodeScanner.cameraAccessDenied) {
setState((){
result = "CAMERA PERMISSION WAS DENIED. \n EDIT THIS IN YOUR SETTINGS";
});
}else {
setState(() {
result = "404 ERROR UNKNOWN $ex";
});
}
} on FormatException {
setState(() {
result = "SCAN AN ITEM";
});
} catch (ex){
setState(() {
result = "404 ERROR UNKNOWN $ex";
});
}
}
#override
void initState() {}
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
} else {
print(response.reasonPhrase);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.teal,
title:Text('Add an item',
style: TextStyle(
fontFamily: 'Fredoka',
fontSize: 25,
),
),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
),
);
else if (snapshot.connectionState == ConnectionState.done)
return ListTile(
title: Text(futuredata["product"]["product_name"].toString()),
subtitle: Text("France:" +
futuredata["product"]["product_name_en"].toString()),
);
else {
return Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
);
}
},
future: fetchmydata(),
)
],
),
floatingActionButton: FloatingActionButton.extended(
backgroundColor: Color.fromRGBO(51, 171, 160, 100),
icon: Icon(Icons.camera_alt),
label: Text("Scan"),
onPressed: _scanBarcode,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
The Json file looks like this:
JSON LINK: https://world.openfoodfacts.org/api/v0/product/5060391623139.json
You can read your json like this
var futuredata = {};
var productname= futuredata["product"]["product_name"]
Your fetch method like this
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
} else {
print(response.reasonPhrase);
}
}
With model Class
SampleModel? Mymodel = null;
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
Mymodel = SampleModel.fromJson(futuredata);
} else {
print(response.reasonPhrase);
}
}
in the method we first read data from json as string or text
then we decode the string type or text from server to map type
SampleCode Dartpad live code check
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:http/http.dart' as p;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
var futuredata = {};
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
#override
void initState() {}
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
} else {
print(response.reasonPhrase);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
),
);
else if (snapshot.connectionState == ConnectionState.done)
return ListTile(
title: Text(futuredata["product"]["product_name"].toString()),
subtitle: Text("France:" +
futuredata["product"]["product_name_en"].toString()),
);
else {
return Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
);
}
},
future: fetchmydata(),
)
],
),
);
}
}
Sample ModelClass
///
/// Code generated by jsonToDartModel https://ashamp.github.io/jsonToDartModel/
///
class SampleModelProduct {
/*
{
"_id": "5060391623139",
"_keywords": [
"peanut"
],
"product_name": "Peanut butter",
"product_name_en": "Peanut butter",
"product_name_fr": "Peanut butter"
}
*/
String? Id;
List<String?>? Keywords;
String? productName;
String? productNameEn;
String? productNameFr;
SampleModelProduct({
this.Id,
this.Keywords,
this.productName,
this.productNameEn,
this.productNameFr,
});
SampleModelProduct.fromJson(Map<String, dynamic> json) {
Id = json['_id']?.toString();
if (json['_keywords'] != null) {
final v = json['_keywords'];
final arr0 = <String>[];
v.forEach((v) {
arr0.add(v.toString());
});
Keywords = arr0;
}
productName = json['product_name']?.toString();
productNameEn = json['product_name_en']?.toString();
productNameFr = json['product_name_fr']?.toString();
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['_id'] = Id;
if (Keywords != null) {
final v = Keywords;
final arr0 = [];
v!.forEach((v) {
arr0.add(v);
});
data['_keywords'] = arr0;
}
data['product_name'] = productName;
data['product_name_en'] = productNameEn;
data['product_name_fr'] = productNameFr;
return data;
}
}
class SampleModel {
/*
{
"code": "5060391623139",
"product": {
"_id": "5060391623139",
"_keywords": [
"peanut"
],
"product_name": "Peanut butter",
"product_name_en": "Peanut butter",
"product_name_fr": "Peanut butter"
},
"status": 1,
"status_verbose": "product found"
}
*/
String? code;
SampleModelProduct? product;
int? status;
String? statusVerbose;
SampleModel({
this.code,
this.product,
this.status,
this.statusVerbose,
});
SampleModel.fromJson(Map<String, dynamic> json) {
code = json['code']?.toString();
product = (json['product'] != null)
? SampleModelProduct.fromJson(json['product'])
: null;
status = json['status']?.toInt();
statusVerbose = json['status_verbose']?.toString();
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['code'] = code;
if (product != null) {
data['product'] = product!.toJson();
}
data['status'] = status;
data['status_verbose'] = statusVerbose;
return data;
}
}
try creating a .g.dart file using flutter packages pub run build_runner build. flutter automatically will create your binding class factory. once you have the binding classes created flutter will automatically code your binding class, including nested classes. I personally think automation is the way to handle all interactions with json from the server. The reason you want to use the future .g.dart code generator is to reduce the possibility of error and incorrect type casting.
file.dart
factory ProductView.fromJson(Map<String, dynamic> json) =>
_$ProductFromJson(json);
Map<String, dynamic> toJson() => _$ProductViewToJson(this);
file.g.dart
ProductView _$ProductViewFromJson(Map<String, dynamic> json) {
return
ProductView(
json['field1'] as int,
json['field2'] as String,
json['field3'] == null
? null
: DateTime.parse(json['field3'] as String),
);
}
Map<String, dynamic> _$ProjectViewToJson(ProductView instance) =>
<String, dynamic>{
'field1': instance.field1,
'field2': instance.field2,
'field3': instance.field3?.toIso8601String(),
};
decoding the json
var client = http.Client();
Map<String, String> headers = new HashMap();
headers['Accept'] = 'application/json';
headers['Content-Type'] = 'application/json';
headers['Authorization'] = 'Bearer $token';
var response = await client.get(url, headers: headers).timeout(_TIMEOUT);
var parsed = json.decode(response.body);
var view = ProductView.fromJson(parsed);

i am trying to fetch slider image using getx but having error

#This is my model class
List<SliderModel> sliderModelFromJson(String str) => List<SliderModel>.from(json.decode(str).map((x) => SliderModel.fromJson(x)));
String sliderModelToJson(List<SliderModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class SliderModel {
SliderModel({
this.id,
this.title,
this.description,
this.image,
this.type,
this.url,
this.schoolid,
});
int id;
String title;
dynamic description;
String image;
String type;
String url;
String schoolid;
factory SliderModel.fromJson(Map<String, dynamic> json) => SliderModel(
id: json["id"],
title: json["title"],
description: json["description"],
image: json["image"],
type: json["type"],
url: json["url"],
schoolid: json["schoolid"],
);
Map<String, dynamic> toJson() => {
"id": id,
"title": title,
"description": description,
"image": image,
"type": type,
"url": url,
"schoolid": schoolid,
};
}
#this is my services class where i call my api
static Future<List<SliderModel>> getSliderData(String id) async{
var dio = don.Dio();
don.Response response =await dio.get("https://shikshyasoftware.com.np/CoreApplicationandAPIService-4617993073/api/shikshyanotice?schoolid=$id") ;
try{
var responseData = response.data;
if(response.statusCode==200){
print("responseData:-${responseData}");
return sliderModelFromJson(jsonEncode(responseData));
}
}catch(e){
rethrow;
}
}
#this is my controller class
class SliderController extends GetxController{
var isLoading = true.obs;
var sliderData = <SliderModel>[];
Future<void> fetchImageSilder(String id) async{
try{
isLoading(true);
var slider = await Services.getSliderData(id);
sliderData = slider;
print(sliderData.length);
}finally{
isLoading(false);
}
}
SliderModel findById(String id){
return sliderData.firstWhere((e) => e.schoolid == id,orElse: ()=>null);
}
}
#this is my view where i tried to call the controller and load the image like this
var isInit = true;
void didChangeDependencies() {
// TODO: implement didChangeDependencies
if(isInit) {
final schoolId = ModalRoute.of(context).settings.arguments;
Get.put(SliderController().fetchImageSilder(schoolId));
}
isInit = false;
super.didChangeDependencies();
}
SliderController sliderData = Get.put(SliderController());
Obx((){
if(sliderData.isLoading.value){
return Center(
child: LinearProgressIndicator(
minHeight: 95.h,
color: Colors.grey.shade100,
backgroundColor: Colors.grey.shade200,
),
);
}else{
return SizedBox(
// height: MediaQuery.of(context).size.height*0.15,
// width: MediaQuery.of(context).size.width*0.99,
height: 95.h,
width: double.infinity,
child:CarouselSlider(
items:sliderData.sliderData.map((e) =>ClipRRect(
borderRadius: BorderRadius.circular(5.r),
child: Stack(
fit: StackFit.expand,
children: [
Image.network(e.image??Image.asset("icons/shik_banner_20200553123753.png"),fit: BoxFit.fill,errorBuilder: (BuildContext context, Object exception, StackTrace stackTrace) {
return Image.asset("icons/shik_banner_20200553123753.png");
},)
],
),
) ).toList()
, options: CarouselOptions(viewportFraction: 1,autoPlay: false,autoPlayAnimationDuration: const Duration(milliseconds: 800),
),
),
);
}
#i am not getting any error but my loading screen continues to load and image is not shown and i am getting show this W/Choreographer(22264): Frame time is 16.052103 ms in the future! Check that graphics HAL is generating vsync timestamps using the correct timebase. in my run and i dont know what to do to load my image need your help thanks in advance
Try to use folllowing code. I will suggest to use the StatefulWidget Widget to call your methods specially if your methods having the paramters. initState helps to call our functions. If you finds this answer helpful please upvote
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _sliderController= Get.put(SliderController());
#override
void initState() {
super.initState();
_sliderController.fetchImageSilder(schoolId);//Here you can pass parameters to your function
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Obx((){
if(sliderData.isLoading.value){
return Center(
child: LinearProgressIndicator(
minHeight: 95.h,
color: Colors.grey.shade100,
backgroundColor: Colors.grey.shade200,
),
);
}else{
return Widget()// Pass your Widget
}
);
}
}
// Getx Controller
class SliderController extends GetxController{
var isLoading = true.obs;
RxList<SliderModel> sliderData = [].obs; // If you are using `Obx()` then your list type should be obs
Future<void> fetchImageSilder(String id) async{
try{
isLoading(true);
var slider = await Services.getSliderData(id);
sliderData.add(slider); // Add your data into `RxList`
print(sliderData.length);
}finally{
isLoading(false);
}
}
SliderModel findById(String id){
return sliderData.firstWhere((e) => e.schoolid == id,orElse: ()=>null);
}
}

findById returns null on hot reload

I have the following dart class which loads an object and an image. When I perform hot reload, the function findById returns an error message Bad State: No element. Upon debugging, I see that the list that I am querying on is null once I do a hot realod. I want to know why that happens and how do I fix this?
class ProductDetailScreen extends StatefulWidget {
static const routeName = '/product-detail';
#override
_ProductDetailScreenState createState() => _ProductDetailScreenState();
}
class _ProductDetailScreenState extends State<ProductDetailScreen> {
var loadedProduct;
var productId;
var _isLoading;
var _imageUrl;
var cartId;
var imagePath = '';
#override
void initState() {
super.initState();
createCartId();
}
Future<void> createCartId()async {
var id = await nanoid(10);
cartId = id;
}
Future<void> didChangeDependencies() async {
productId = ModalRoute.of(context).settings.arguments as String;
imagePath = productId;
setState(() {
_isLoading = true;
});
final myCacheManager = MyCacheManager();
await myCacheManager.cacheImage(imagePath).then((String imageUrl) {
setState(() {
_imageUrl = imageUrl;
_isLoading = false;
});
});
}
#override
Widget build(BuildContext context) {
loadedProduct = Provider.of<Products>(context,listen:false).findById(productId);
Size size = MediaQuery.of(context).size;
var userId = Provider.of<Auth>(context, listen: false).userId;
return !(_isLoading)?Scaffold(
appBar: AppBar(
actions: null,
title: Text(loadedProduct.title),
),
body:
CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child:
Column(
children: <Widget>[
Container(
height: size.height * 0.35,
width: double.infinity,
child:_imageUrl != 'No picture loaded'?
CachedNetworkImage(
imageUrl: _imageUrl,
progressIndicatorBuilder: (context, url, downloadProgress) =>
Center(child:Loading()),
errorWidget: (context, url, error) => Image.asset('assets/images/placeholder.png'),
)
:Image.asset('assets/images/placeholder.png'),
),
Expanded(
child: ItemInfo(
cartId,
loadedProduct.id,
loadedProduct.title,
loadedProduct.price,
loadedProduct.description,
loadedProduct.categoryName,
loadedProduct.isAvailable),
),
],
))]))
:Center(child:Loading());
}
}
class ItemInfo extends StatefulWidget {
ItemInfo(this.cartId,this.id,this.name,this.price,this.description,this.category,this.isAvailable);
var id;
var cartId;
var name;
var price;
var description;
var category;
var isAvailable;
#override
_ItemInfoState createState() => _ItemInfoState();
}
class _ItemInfoState extends State<ItemInfo> {
bool changePrice = false;
List<String> selectedItems;
#override
Widget build(BuildContext context) {
return
Container(
padding: EdgeInsets.all(15),
width: double.infinity,
decoration: BoxDecoration(
boxShadow: [BoxShadow(color: Colors.orange, spreadRadius: 1)],
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30),
),
),
child:
Column(
children: <Widget>[
TitlePriceRating(
name: widget.name,
price: widget.price,
),
],
),
);
}
}
Here's the function function findById
Product findById(String id) {
return _items.firstWhere((prod) => prod.id == id);
}
Here's the function which sets the _items list:
Future<void> fetchAndSetProducts(String title) async {
var encodedTitle = Uri.encodeComponent(title);
var url = 'https://mm-nn-default-rtdb.firebaseio.com/products.json?auth=$authToken';
try {
final response = await http.get(Uri.parse(url));
final extractedData = json.decode(response.body) as Map<String, dynamic>;
final List<Product> loadedProducts = [];
if (extractedData == null || extractedData['error'] != null) {
_items = loadedProducts;
return _items;
}
extractedData.forEach((prodId, prodData) {
loadedProducts.add(Product(
id: prodId,
title: prodData['title'],
description: prodData['description'],
price: prodData['price'],
categoryName: prodData['categoryName'],
));
});
notifyListeners();
_items = loadedProducts;
return _items;
} catch (error) {
throw (error);
}
}
This function is called in a class called ProductOverviewScreen which then calls a class called ProductGrid. ProductGrid basically contains a listviewbuilder of the products. This class then calls ProductItem which is basically a single product in the product list. ProductItem contains a button which when clicked, calls ProductDetailsScreen which is the class causing the error.
Use setState method.
Future<void> didChangeDependencies() async {
setState(() {
productId = ModalRoute.of(context).settings.arguments as String;
imagePath = productId;
_isLoading = true;
});
final myCacheManager = MyCacheManager();
await myCacheManager.cacheImage(imagePath).then((String imageUrl) {
setState(() {
_imageUrl = imageUrl;
_isLoading = false;
});
});
}
replace
return _items.firstWhere((prod) => prod.id == id);
with
return _items.firstWhere((prod) => prod.id == id, orElse: () => null,);
The problem is in this code.
extractedData.forEach((prodId, prodData) {
loadedProducts.add(Product(
id: prodId,
title: prodData['title'],
description: prodData['description'],
price: prodData['price'],
categoryName: prodData['categoryName'],
));
});
In this code, you are directly adding the product to the state. The state is immutable. So make a temporary list there add all the data into the temporary list and finally use setState() to put the temporary list data into the state. The code should be like this.
List<Product> tempList = [];
extractedData.forEach((prodId, prodData) {
tempList.add(Product(
id: prodId,
title: prodData['title'],
description: prodData['description'],
price: prodData['price'],
categoryName: prodData['categoryName'],
));
});
setState((){
loadedProducts = tempList;
})