flutter sqflite+getx use group_button to filter the array from database and render GridView.builder - flutter-getx

I am using flutter desktop development. Use the group button filter to read data from the database and render it to GridView.builder().
At present, I can't realize the filtering function when I read the data sheet from the database[enter image description here][1]
I am using getx
final selected = 'table_operation'.obs;
final items = ['table_operation', 'merge_table', 'turn_table'];
final SqliteHelper _sqliteHelper = SqliteHelper();
final areas = [].obs;
final selectedAreaType = 0.obs;
final tables = [].obs;
// final filterTables = [].obs;
var areaModel;
final areaId = 0.obs;
void setSelected(value) {
selected.value = value;
}
void setSelectArea(int value) {
selectedAreaType.value = value;
areaModel = areas[selectedAreaType.value];
areaId.value = areaModel.id;
}
#override
onInit() {
getAreaList();
getTableList();
super.onInit();
}
Future<List<AreaModel>> getAreaList() async {
List<Map<String, dynamic>> results = await _sqliteHelper.queryObject('area');
List<AreaModel> areaList = [];
for (var r in results) {
if (r.isNotEmpty) {
areaList.add(AreaModel.fromMap(r));
}
}
areas.value = areaList.map((e) => e).toList();
return areaList;
}
Future<List<TableModel>> getTableList() async {
List<Map<String, dynamic>> results = await _sqliteHelper.queryObject('tables');
List<TableModel> tableList = [];
for (var t in results) {
tableList.add(TableModel.fromMap(t));
}
tables.value = tableList.map((e) => e).toList();
return tableList;
}
[1]: https://i.stack.imgur.com/fOGwg.png

Related

NotifyListner is not working for List<String> and working for other object

In SearchData class any change in result update the UI but any change in history, is not updating the UI, even tho the implemenation of both is same. I'm calling notify for both of em.
Below is the class code
class SearchData<T> {
List<R> copyList<R>(List<R>? list) => List.from(list ?? []);
SearchData(this.notify, this.historyKey) {
_loadHistory();
}
final void Function([VoidCallback? action]) notify;
final String historyKey;
int page = 1;
List<T>? _result;
List<T>? get result => _result;
// search history
List<String> _history = [];
List<String> get history => _history;
void _loadHistory() async {
final data = await DataBox(historyKey).readStringList();
if (kDebugMode) {
print('hello loaded history = $data');
}
if (data != null) notify(() => _history = copyList(data));
}
void updateSearchResult(String query, List<T>? newResult, bool isLoadMore) {
if (newResult == null) return;
notify(() {
if (isLoadMore) {
_result = copyList(result)..addAll(newResult);
} else {
_result = newResult;
}
});
// save local history of search
if (!_history.contains(query)) {
_history.add(query);
DataBox(historyKey).writeStringList(history);
}
}
}
I tried the workoaroud of creating new instance of list, so notify listner could update the UI.

Why is ChangeNotifier updating endlessly

I have 2 data provider classes that extend ChangeNotifier. Within each, there's a function to fetch data and at the end of them, I use notifyListeners() to notify the screens/listeners that the data changed. However, it seems that the listeners start getting notified endlessly instead of once and that creates a loop of reloading, circle indicators that don't go away, and a frozen screen. I don't get it.
Data providers:
class UsersDataProvider extends ChangeNotifier {
UsersDataProvider() : super();
static Map<int, QueryDocumentSnapshot<Object?>> usersMap = {};
Future<void> fetchUsers() async {
final userRef = FirebaseFirestore.instance.collection('users');
final QuerySnapshot result = await userRef.get();
final docs = result.docs.asMap();
usersMap = docs;
print(usersMap.length);
notifyListeners();
}
}
class PostsDataProvider extends ChangeNotifier {
PostsDataProvider() : super();
static Map<int, QueryDocumentSnapshot<Object?>> postsMap = {};
Future<void> fetchPosts() async {
UsersDataProvider.usersMap.forEach((index, resultValue) async {
final postsRef = FirebaseFirestore.instance
.collection('users')
.doc(resultValue.id)
.collection('posts');
final QuerySnapshot postsResult = await postsRef.get();
final postDocs = postsResult.docs.asMap();
postsMap = postDocs;
print('Post map: ${postsMap.length}');
notifyListeners();
});
}
}
Add listeners and reload data:
Future<void> fetchUsersAndPosts(bool initial) async {
if (!initial) {
setState(() {
postsLoading = true;
});
usersDataProvider.fetchUsers();
postsDataProvider.fetchPosts();
}
if (initial) {
usersDataProvider.addListener(() {
print('changed');
setState(() {
fetchUsersAndPosts(false);
});
});
}
if (initial) {
postsDataProvider.addListener(() {
setState(() {
fetchUsersAndPosts(false);
});
});
}
UsersDataProvider.usersMap.forEach((index, value) async {
List<Post> posts = [];
PostsDataProvider.postsMap.forEach((index, value) {
final post = Post.fromJson(value.data() as Map<String, dynamic>);
posts.add(post);
setState(() {});
if (posts.length == PostsDataProvider.postsMap.length) {
setState(() {
postsList = posts;
postsList.sort((a, b) {
return b.date.compareTo(a.date);
});
postsLoading = false;
});
}
});
final profileInfo =
ProfileInfoObject.fromJson(value.data() as Map<String, dynamic>);
Profile profile = Profile(profileInfo, postsList.where((p) => p.uid == value.id).toList());
UserSearchResult user = (UserSearchResult(profile, value.id));
if (usersList.where((u) => u.uid == user.uid).toList().isEmpty) {
setState(() {
usersList.add(user);
});
}
});
setState(() {
postsList.sort((a, b) {
return b.date.compareTo(a.date);
});
});
}

Data is showing only after hot reload

I'm new to flutter and amplify. I'm trying to do an app using flutter and amplify as backend. I want to retrieve data from three datastore table at once and put them in to a List<Map<String, dynamic>>. I can read data from the List but the data display only when I press refresh or hot reload. I think maybe the mistake is the way I put the setstate? Could anyone tell me what I did wrong? Any help would be much appreciated!
Here is my code
late StreamSubscription _subscription;
List<Map<String, dynamic>> _orderList = [];
#override
void initState() {
super.initState();
_subscription =
Amplify.DataStore.observe(OrderItem.classType).listen((event) {
_fetchOrder();
});
_orderList = [];
_fetchOrder();
}
Future _fetchOrder() async {
List<Map<String, dynamic>> fullOrderItemList = [];
// fetch all order by user id
final user = await Amplify.Auth.getCurrentUser();
List<Order> orderDb = await Amplify.DataStore.query(Order.classType,
where: Order.USERID.eq(user.userId));
// fetch order item and user name by order id & user id
orderDb.asMap().forEach((index, order) async {
List<Map<String, String>> orderItemByOrderId = [];
User buyerInfo = (await Amplify.DataStore.query(User.classType,
where: User.ID.eq(order.userID)))[0];
List<OrderItem> orderitem = await Amplify.DataStore.query(
OrderItem.classType,
where: OrderItem.ORDERID.eq(order.id));
orderitem.asMap().forEach((index, orderitem) {
orderItemByOrderId.add({
"order item id": orderitem.id,
"item name": orderitem.item,
"price": orderitem.price.toString(),
"quantity": orderitem.quantity.toString(),
});
});
fullOrderItemList.add({
'order id': order.id,
'order date': order.orderDate,
'total price': order.totalPrice.toString(),
'buyer name': buyerInfo.name,
'buyer phone': buyerInfo.phone,
'buyer email': buyerInfo.email,
'order item': orderItemByOrderId,
});
});
setState(() {
_orderList = fullOrderItemList;
});
}
You should use await with _fetchOrder().
One way to get around this would be to make _fetchOrder() return the fullOrderItemList and use setState inside Future.then:
#override
void initState() {
super.initState();
_subscription =
Amplify.DataStore.observe(OrderItem.classType).listen((event) {
_fetchOrder().then((orderList) => setState(() {
_orderList = orderList;
});
});
_orderList = [];
_fetchOrder().then((orderList) => setState(() {
_orderList = orderList;
});
}
If this doesn't work, you can try this:
_fetchOrder().then((orderList) {
WidgetsBinding.instance!.addPostFrameCallback((_) => setState(() {
_orderList = orderList;
})}
);

Parse data Map from json fail, how to fix

I've method search from api, data model like object, but i don't know how to parse, anyone can help me let see my code below, i have search method and api link, if u wanna other code, u can comment on column comment
import 'package:get/get.dart';
import 'package:resto_app/app/models/detail_model.dart';
import 'package:resto_app/shared/constant/api_services.dart';
import 'package:resto_app/shared/services/base_client.dart';
class SearchController extends GetxController {
//TODO: Implement SearchController
RxBool isAwaitData = false.obs;
// RxList<DetailModel> ;
Future<List<DetailModel>> searchController(
{String query = '', bool isWait = true}) async {
if (isWait) {
isAwaitData.value = true;
List result = await BaseClient().get(
baseUrl: ApiService.baseURL, api: ApiService.searchResto + query);
// var response = await http
// .get(Uri.parse(ApiService.baseURL + ApiService.searchResto + query));
return result.map((e) => DetailModel.fromJson(e)).where((resto) {
final nameLower = resto.restaurant.name.toLowerCase();
final cityLower = resto.restaurant.city.toLowerCase();
final searchLower = query.toLowerCase();
return nameLower.contains(cityLower);
}).toList();
} else {
throw Exception();
}
// if (response.statusCode == 200) {
// final result = Map<String, dynamic>.from(jsonDecode(response.body));
// result.map((key, value) =>
// key.contains(result)
// );
// }
}
}
class ApiService {
static const baseURL = 'https://restaurant-api.dicoding.dev';
static const allResto = '/list';
static const detailPage = '/detail/';
static const searchResto = '/search?q=';
}
The API doesn't return a list, but a map - The restaurants key of the response points to a list of objects.
Try:
final Map<String, dynamic> responseData = await BaseClient().get(
baseUrl: ApiService.baseURL,
api: ApiService.searchResto + query
);
final restaurantData = responseData['restaurants'];
return restaurantData.map((e) => DetailModel.fromJson(e)).where((resto) {
final nameLower = resto.restaurant.name.toLowerCase();
final cityLower = resto.restaurant.city.toLowerCase();
final searchLower = query.toLowerCase();
return nameLower.contains(cityLower);
}).toList();

Flutter SharedPreferences how to load all saved?

How can I load all saved in SharedPreferences?
I have saved lots of bools and need to load all to a list!
This is how I save:
SharedPreferences sharedPreferences;
bool isfavorit;
#override
void initState() {
super.initState();
SharedPreferences.getInstance().then((SharedPreferences sp) {
sharedPreferences = sp;
isfavorit = sharedPreferences.getBool('${widget.id}');
// will be null if never previously saved
if (isfavorit == null) {
isfavorit = false;
persist(isfavorit); // set an initial value
}
setState(() {});
});
}
void persist(bool value) {
setState(() {
isfavorit = value;
});
sharedPreferences?.setBool('${widget.id}', value);
}
List<bool> prefList = [];
var sharedPreferences = await SharedPreferences.getInstance();
Set<String> keys = sharedPreferences.getKeys();
for(int i=0; i<keys.length ; i++){
bool value = sharedPreferences.getBool(keys.elementAt(i));
prefList.add(value);
}
If you have non bool value too in your persistent storage, you have to use the recognisable key to store those value.
For example :- sharedPreferences.setBool('bool${widget.id}', value);
Now this special keyword can be used to know if it is a bool value or not
List<bool> prefList = [];
var sharedPreferences = await SharedPreferences.getInstance();
Set<String> keys = sharedPreferences.getKeys();
for(int i=0; i<keys.length ; i++){
if(key.elementAt(i).contains('bool')){
bool value = sharedPreferences.getBool(keys.elementAt(i));
prefList.add(value);
}
}
Edit:- You have to use the code inside a function and return you string
Example:-
Future<List<bool>> getBoolList() async{
List<bool> prefList = [];
var sharedPreferences = await SharedPreferences.getInstance();
Set<String> keys = sharedPreferences.getKeys();
for(int i=0; i<keys.length ; i++){
bool value = sharedPreferences.getBool(keys.elementAt(i));
prefList.add(value);
}
return prefList;
}
Then call this function
List<bool> list = await getBoolList();
Note :- In simple words, only asynchronous functions will allow you to use await keyword inside them, and if they return something, that will be Future.