Searchable Dropdown with Flutter, Mobx and Sqlite - flutter

I am tryng implement a Searchable Dropdown package:
https://github.com/salim-lachdhaf/searchable_dropdown
I am using mobx and Sqlite
See Widget Code:
DropdownSearch<TarefaModel>(
label: 'BUSCAR TAREFAS',
onFind: (String filter) =>
controller.filtrarTarefas(filter),
onChanged: (TarefaModel data) {
print(data);
},
dropdownBuilder: _customDropDownExample,
),
My Mobx action:
Controller action:
#observable
ObservableList<TarefaModel> tarefas = new ObservableList<TarefaModel>();
#action
filtrarTarefas(termo) async {
final repository = new TarefaRepository();
tarefas = new ObservableList<TarefaModel>();
var data = await repository.search(termo);
tarefas.addAll(data);
return tarefas;
}
Custom DropDown:
Widget _customDropDownExample(
BuildContext context, TarefaModel item, String itemDesignation) {
return Container(
child: Observer(
builder: (_) => ListView.builder(
itemCount: controller.tarefas.length,
itemBuilder: (context, i) {
return ListTile(
title: Text(item.descricao),
subtitle: Text(item.label),
);
})),
);
}
My Model:
class TarefaModel{
int id;
String descricao;
TarefaModel({this.id, this.descricao});
Map<String, dynamic> toMap() {
return {'id': id,'descricao': descricao};
}
}
But this erros is show:
Any idea? Thanks

My repository:
Future<List<TarefaModel>> search(String term) async {
try {
final Database db = await _getDatabase();
final List<Map<String, dynamic>> maps = await db.query(
TAREFAS_TABLE,
where: "descricao LIKE ?",
whereArgs: [
'%$term%',
],
);
return List.generate(
maps.length,
(i) {
return TarefaModel(
id: maps[i]['id'],
descricao: maps[i]['descricao'],
);
},
);
} catch (ex) {
print(ex);
return new List<TarefaModel>();
}
}

Related

getting an error type int is not a subtype of string

I creating a demo for sqlite where I have created a model class category model and in sqlite I have created some default categories in its on create method and now want to show all categories on home screen using future builder but its execute error part of feature builder..and app starts with center text
type int is not a subtype of string
category model
class CategoryModel{
String title;
IconData icon;
int entries;
double totalamount;
CategoryModel({required this.title,this.entries=0,required this.icon,this.totalamount=0.0});
Map<String,dynamic> tomap()
{
return {
'title':title,
'entries':entries,
'totalamount':totalamount.toString()
};
}
factory CategoryModel.frommap(Map<String,dynamic> map)
{
return CategoryModel(
title: map['title'],
icon: icons[map['title']]!,
entries: map['entries'],
totalamount: double.parse(map['totalamount'])
);
}
}
this is the widget where I am using futurebuilder
Widget getbody()
{
return FutureBuilder(
future: SqfliteProvider.fetchcategory(),
builder: (context,AsyncSnapshot<List<CategoryModel>?>snapshot){
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()+' Founded'),
);
} else if (snapshot.hasData) {
if (snapshot.data != null) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
CategoryModel t = snapshot.data![index];
print(t.title.toString());
print(' ');
print(t.entries.toString());
print(' ');
print(t.totalamount.toString());
return Card(
child: ListTile(
leading: CircleAvatar(
child: Icon(icons[t.title]),
),
title: Text(t.title.toString(),style: TextStyle(fontSize: 18,fontWeight: FontWeight.bold),),
subtitle:Text(
"Entries :"+t.entries.toString(),
style: TextStyle(fontSize: 14),
) ,
),
);
});
} else {
return Text('Something wrong');
}
} else {
return Text('Last if');
}
},
);
}
this is my database helper class
class SqfliteProvider {
static Future<Database> _getdb() async {
return openDatabase(join(await getDatabasesPath(), 'expensedb1.db'),
version: 1,
onCreate: (db,version) {
db.execute("CREATE TABLE categorytb(title TEXT NOT NULL,entries INTEGER NOT NULL,totalamount STRING NOT NULL)");
//add some default categories
print('I am ready to call');
for(int x=0;x<icons.length;x++)
{
db.insert('categorytb', {
'title':icons.keys.toList()[x],
'entries':0,
'totalamount':(0.0).toString()
});
}
});
}
static Future<List<CategoryModel>?> fetchcategory() async{
final db=await _getdb();
List<CategoryModel> templist=[];
List<Map<String,dynamic>> maplist=await db.query('categorytb');
print(maplist.toString());
if(maplist.isEmpty)
return null;
templist=maplist.map((e) => CategoryModel.frommap(e)).toList();
return templist;
}
}
Try to convert toString.
factory CategoryModel.frommap(Map<String, dynamic> map) {
IconData getIconData(data) {
try {
return IconData(data);
} catch (e) {
return IconData(Icons.abc.codePoint);
}
}
return CategoryModel(
title: map['title'].toString(),
icon: getIconData(map['title']), // pass different data if needed
entries: int.tryParse(map['entries'].toString()) ?? 0,
totalamount: double.tryParse(map['totalamount']) ?? 0,
);
}

Flutter - How to fix `Instance of 'Future<int>'` when querying SQLite database

Since I want to test foreign key features with SQLite, I am trying to make a simple app.
The app should display inventory information like this:
I made two tables on the SQLite database and added records directly by querying on Android Studio's Database Inspector.
items table
prices table
I tried to get each item's price by querying in the app, but Instance of 'Future<int>' displayed. How can I display item prices correctly?
Main code
class SqliteForeignKeyScreen extends StatefulWidget {
const SqliteForeignKeyScreen({
Key? key,
}) : super(key: key);
#override
State<SqliteForeignKeyScreen> createState() => _SqliteForeignKeyScreenState();
}
class _SqliteForeignKeyScreenState extends State<SqliteForeignKeyScreen> {
Future<List<Item>>? _itemsList;
void _updateItemsList() {
setState(() {
_itemsList = DatabaseHelper.instance.getAllItemsList();
});
}
#override
void initState() {
super.initState();
_updateItemsList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Items'),
),
body: FutureBuilder(
future: _itemsList,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
Text('ERROR: ${snapshot.error}');
}
if (snapshot.hasData == false) {
return const CircularProgressIndicator();
}
if (snapshot.data.length == null || snapshot.data.length == 0) {
return const Text('no items');
}
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
return _buildItemCards(snapshot.data[index]);
});
},
),
);
}
_buildItemCards(Item item) {
var price = DatabaseHelper.instance.getItemPrice(item.id!);
print('item: ${item.name}, price: ${price}G');
return Card(
child: ListTile(
title: Text(item.name),
subtitle: Text('${price}G'),
),
);
}
}
database_helper.dart
class DatabaseHelper {
static final DatabaseHelper instance = DatabaseHelper._instance();
static Database? _db;
DatabaseHelper._instance();
Future<Database?> get db async {
_db ??= await _initDb();
return _db;
}
void _configureDb(Database db) async {
await db.execute('PRAGMA foreign_keys = ON;');
}
void _createDb(Database db, int version) async {
await db.execute('CREATE TABLE items('
'id INTEGER PRIMARY KEY AUTOINCREMENT,'
'name TEXT'
');');
await db.execute('CREATE TABLE prices('
'id INTEGER PRIMARY KEY AUTOINCREMENT,'
'item_id INTEGER,'
'price INTEGER,'
'FOREIGN KEY(item_id) REFERENCES items(id)'
');');
}
Future<Database> _initDb() async {
var databasePath = await getDatabasesPath();
String path = p.join(databasePath, 'inventory.db');
final inventoryDb = await openDatabase(path,
version: 1, onConfigure: _configureDb, onCreate: _createDb);
return inventoryDb;
}
Future<List<Map>> getAllItemsMapList() async {
Database? db = await this.db;
final List<Map<String, dynamic>> result = await db!.query('items');
return result;
}
Future<List<Item>> getAllItemsList() async {
final List<Map> itemsMapList = await getAllItemsMapList();
final List<Item> itemsList = [];
for (var itemMap in itemsMapList) {
itemsList.add(Item.fromMap(itemMap));
}
return itemsList;
}
Future<int> getItemPrice(int itemId) async {
final Database? db = await this.db;
final result =
await db!.query('prices', where: 'item_id = ?', whereArgs: [itemId]);
return result[0]['price'] as int;
}
}
item_model.dart
class Item {
int? id;
String name;
Item({
required this.name,
});
Item.withId({
this.id,
required this.name,
});
factory Item.fromMap(Map map) {
return Item.withId(
id: map['id'],
name: map['name'],
);
}
}
Result of print('item: ${item.name}, price: ${price}G');
item: Apple, price: Instance of 'Future<int>'G
item: Banana, price: Instance of 'Future<int>'G
item: Chocolate, price: Instance of 'Future<int>'G
When I changed _buildItemCards like this (added await and async):
_buildItemCards(Item item) async {
var price = await DatabaseHelper.instance.getItemPrice(item.id!);
print('item: ${item.name}, price: ${price}G');
return Card(
child: ListTile(
title: Text(item.name),
subtitle: Text('${price}G'),
),
);
}
The print('item: ${item.name}, price: ${price}G'); shows correctly:
item: Apple, price: 2G
item: Banana, price: 1G
item: Chocolate, price: 3G
However, the error type 'Future<dynamic>' is not a subtype of type 'Widget' occurred on the screen.
The getItemPrice is a Future function, so you should await for its result, like this:
var price = await DatabaseHelper.instance.getItemPrice(item.id!);
And also the best way to use async function in build method is using FutureBuilder, so change your _buildItemCards to this:
FutureBuilder<int>(
future: DatabaseHelper.instance.getItemPrice(item.id!),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
int price = snapshot.data!;
return Card(
child: ListTile(
title: Text(item.name),
subtitle: Text('${price}G'),
),
);
}
}
},
)

Fetching data from API and storing it to local database error

I'm trying to store data that fetched from API using sqflite
Now I'm getting an error saying...
A value of type 'List' can't be returned from the method 'getAllEmployees' because it has a return type of 'Future<List>'.
Here's my employee_provider.dart file
class EmployeeApiProvider {
Future<List<Employee>> getAllEmployees() async {
var url = "http://demo8161595.mockable.io/employee";
var response = await Dio().get(url);
return employeeFromJson(response.data).map((employee) {
DBProvider.db.createEmployee(employee);
}).toList();
}
}
How to fix this?
And other files relevant to this are...
db_provider.dart
class DBProvider {
static Database? _database;
static final DBProvider db = DBProvider._();
DBProvider._();
Future<Database?> get database async {
if (_database != null) return _database;
_database = await initDB();
return _database;
}
initDB() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
final path = join(documentsDirectory.path, 'employee_manager.db');
return await openDatabase(path, version: 1, onOpen: (db) {},
onCreate: (Database db, int version) async {
await db.execute('CREATE TABLE Employee('
'id INTEGER PRIMARY KEY,'
'email TEXT,'
'firstName TEXT,'
'lastName TEXT,'
'avatar TEXT'
')');
});
}
createEmployee(Employee newEmployee) async {
await deleteAllEmployees();
final db = await database;
final res = await db!.insert('Employee', newEmployee.toJson());
return res;
}
Future<int> deleteAllEmployees() async {
final db = await database;
final res = await db!.rawDelete('DELETE FROM Employee');
return res;
}
Future<List<Employee>> getAllEmployees() async {
final db = await database;
final res = await db!.rawQuery("SELECT * FROM EMPLOYEE");
List<Employee> list =
res.isNotEmpty ? res.map((c) => Employee.fromJson(c)).toList() : [];
return list;
}
}
employee_model.dart
List<Employee> employeeFromJson(String str) =>
List<Employee>.from(json.decode(str).map((x) => Employee.fromJson(x)));
String employeeToJson(List<Employee> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Employee {
int id;
String email;
String firstName;
String lastName;
String avatar;
Employee({
required this.id,
required this.email,
required this.firstName,
required this.lastName,
required this.avatar,
});
factory Employee.fromJson(Map<String, dynamic> json) => Employee(
id: json["id"],
email: json["email"],
firstName: json["firstName"],
lastName: json["lastName"],
avatar: json["avatar"],
);
Map<String, dynamic> toJson() => {
"id": id,
"email": email,
"firstName": firstName,
"lastName": lastName,
"avatar": avatar,
};
}
home.dart
class _HomeState extends State<AbcView> {
var isLoading = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Api to sqlite'),
centerTitle: true,
actions: <Widget>[
Container(
padding: const EdgeInsets.only(right: 10.0),
child: IconButton(
icon: const Icon(Icons.settings_input_antenna),
onPressed: () async {
await _loadFromApi();
},
),
),
Container(
padding: const EdgeInsets.only(right: 10.0),
child: IconButton(
icon: const Icon(Icons.delete),
onPressed: () async {
await _deleteData();
},
),
),
],
),
body: isLoading
? const Center(
child: CircularProgressIndicator(),
)
: _buildEmployeeListView(),
);
}
_loadFromApi() async {
setState(() {
isLoading = true;
});
var apiProvider = EmployeeApiProvider();
await apiProvider.getAllEmployees();
await Future.delayed(const Duration(seconds: 2));
setState(() {
isLoading = false;
});
}
_deleteData() async {
setState(() {
isLoading = true;
});
await DBProvider.db.deleteAllEmployees();
await Future.delayed(const Duration(seconds: 1));
setState(() {
isLoading = false;
});
}
_buildEmployeeListView() {
return FutureBuilder(
future: DBProvider.db.getAllEmployees(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
return ListView.separated(
separatorBuilder: (context, index) => const Divider(
color: Colors.black12,
),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Text(
"${index + 1}",
style: const TextStyle(fontSize: 20.0),
),
title: Text(
"Name: ${snapshot.data[index].firstName} ${snapshot.data[index].lastName} "),
subtitle: Text('EMAIL: ${snapshot.data[index].email}'),
);
},
);
}
},
);
}
}
Maybe you could try to add await in front of the DBProvider.db.createEmployee?
class EmployeeApiProvider {
Future<List<Employee>> getAllEmployees() async {
var url = "http://demo8161595.mockable.io/employee";
var response = await Dio().get(url);
return employeeFromJson(response.data).map((employee) async {
await DBProvider.db.createEmployee(employee);
}).toList();
}
}

error in implementing search feature in Listview builder

I'm trying to implement search functionality in the list view builder But I don't have an idea to implement it.
this is model class
class Contacts {
String? id;
String? name;
String? display_name;
Contacts({this.id, this.name, this.display_name});
factory Contacts.fromJson(Map<String?, dynamic> json) {
return Contacts(
id: json['id'], name: json['name'], display_name: json['display_name']);
}
Map toJson() => {'id': id, 'name': name, "display_name": display_name};
}
this is the future class
late Future<List<Contacts>> c;
void onInit() async {
c = getContacts();
}
Future<List<Contacts>> getContacts() async {
print("<<<<<GETTING CONTACTS>>>>>>");
// SERVER API URL
Uri url = Uri.parse('http://localhost:8000/get-contacts');
// Store all data with Param Name.
var data = {'sender': id};
//json encode
String? body = json.encode(data);
// Starting Web API Call.
var response = await http.post(url,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: body);
// If Web call Success than Hide the CircularProgressIndicator.
if (response.statusCode == 200) {
final datas = json.decode(response.body).cast<Map<String, dynamic>>();
contacts = datas.map<Contacts>((json) {
return Contacts.fromJson(json);
}).toList();
print(contacts);
return contacts;
} else {
return contacts = [];
}
}
this is view class
FutureBuilder<List<Contacts>>(
future: controller.c,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: (context, index) {
return Card(
child: CheckboxListTile(
title: Text(
snapshot.data![index].name ?? "name"),
value: controller.isChecked[index],
onChanged: (val) {
setState(
() {
print(snapshot.data![index]);
controller.selectContact(
index, val, snapshot.data![index]);
},
);
},
),
);
},
);
}
}),
anyone, please help me to filter the records from the snapshot data.
I successfully implemented it in listview but not in listviewBuildr

Provider not getting data from database

I was trying to make a simple cart app which loads cart data from database. actually loads data from database to provider. but when we add item to cart and close the app, when It comes back cart hasn't any item.
fetchCartProducts called to get data from database, it must give to the provider cartItems. but it stores data in database, not showing it when it's closed.
home_screen.dart
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
Future<List<FoodItem>> _foodItems;
#override
void initState() {
super.initState();
_foodItems = ApiService.getFoodItems();
Provider.of<CartProvider>(context, listen: false).fetchCartProducts();
}
#override
Widget build(BuildContext context) {
final cart = Provider.of<CartProvider>(context, listen: false);
return Scaffold(
appBar: AppBar(
title: const Text('Food Cart'),
actions: [
Consumer<CartProvider>(
builder: (_, cartprovider, ch) => Badge(
child: ch,
value: cartprovider.itemCount.toString(),
),
child: IconButton(
icon: Icon(Icons.shopping_cart),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) {
return CartScreen();
}),
);
},
),
),
],
),
body: FutureBuilder<List<FoodItem>>(
future: _foodItems,
builder: (conext, snapshot) => !snapshot.hasData
? const Center(
child: CircularProgressIndicator(),
)
: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
FoodItem foodItem = snapshot.data[index];
return ListTile(
title: Text(foodItem.productName),
subtitle: Text(foodItem.variant),
trailing: IconButton(
onPressed: () {
cart.addToCart(
foodItem.storeid.toString(),
foodItem.productName,
1,
foodItem.price,
);
setState(() {});
},
icon: const Icon(Icons.shopping_cart),
),
);
},
),
),
);
}
}
cart_provider.dart
class CartProvider with ChangeNotifier {
Map<String, CartModel> _cartItems = {};
Map<String, CartModel> get cartItems {
return {..._cartItems};
}
int get itemCount {
return _cartItems.length;
}
void reduceItem(
String productId,
String productName,
int quantity,
double price,
) {
if (quantity == 1) {
_cartItems.remove(productId);
notifyListeners();
} else {
_cartItems.update(
productId,
(cartItem) => CartModel(
productId,
cartItem.price,
productName,
cartItem.quantity - 1,
),
);
notifyListeners();
}
}
void addItem(String productId, String productName, double price) {
if (_cartItems.containsKey(productId)) {
//add quantity
_cartItems.update(productId, (existingCartItem) {
return CartModel(
existingCartItem.id,
existingCartItem.price,
existingCartItem.productName,
existingCartItem.quantity + 1,
);
});
}
notifyListeners();
}
void addToCart(
String productId, String productName, int quantity, double price) {
_cartItems.putIfAbsent(
productId,
() {
DBHelper.insert('cart_food', {
'id': productId,
'productName': productName,
'quantity': quantity,
'price': price,
});
return CartModel(
productId,
price,
productName,
1,
);
},
);
notifyListeners();
}
double get totalAmount {
var total = 0.0;
_cartItems.forEach((key, cartItem) {
total += cartItem.price * cartItem.quantity;
});
return total;
}
void removeItem(String productId) async {
_cartItems.remove(productId);
notifyListeners();
await DBHelper.delete(productId);
}
Future<void> fetchCartProducts() async {
List<Map<String, CartModel>> dataList = await DBHelper.getData('cart_food');
print(dataList);
//_cartItems = dataList.map((e) => )
_cartItems = dataList as Map<String, CartModel>;
}
}
getData
static Future<List<Map<String, CartModel>>> getData(String table) async {
final db = await DBHelper.database();
return db.query(table);
}
What did I wrong? I don't get it. please help
Is the data successfully uploaded to the database?
If so, here's what could be going wrong -- You're fetching the products in initState() as follows:
Provider.of<CartProvider>(context, listen: false).fetchCartProducts();
The problem here is "context".
Generally, for a widget the perfect place to initialize and listen for data from the web is the initState() method. However "context" doesn't work in initState() because "context" comes into play after initState() is called. So, you can't invoke your provider class there.
Try to use didChangeDependencies instead as follows:
var _isInit=true;
#override
void didChangeDependencies() {
if(_isInit){
_foodItems = ApiService.getFoodItems();
Provider.of<CartProvider>(context,listen:false).fetchCartProducts();
_isInit=false;
}
super.didChangeDependencies();
}
Lmk if this works.