How to search and display results from an array field in cloud firestore in flutter? - flutter

The logic behind my search function is, The searchKey field stored a value's capitalized first letter. Basically, I will store any value with it's searchKey; which is the values First letter capitalized and stored in a new field called SearchKey.
I wanted to display searched results from an array in Cloud Firestore. The code I have written for a string field works perfectly. Here it is:
void initiateSearch(String val) async {
if (val.length == 0) {
setState(() {
queryResultSet = [];
tempSearchStore = [];
queryResultGigSet = [];
tempSearchGigStore = [];
queryResultTagSet = [];
tempSearchTagStore = [];
});
}
String capitalizedValue =
val.substring(0, 1).toUpperCase() + val.substring(1);
if (queryResultGigSet.length == 0 && val.length == 1) {
// SearchService().searchByName(val);
await databaseReference
.collection('posts')
.where('searchKey', isEqualTo: val.substring(0, 1).toUpperCase())
.getDocuments()
.then((QuerySnapshot docs) {
for (int i = 0; i < docs.documents.length; ++i) {
setState(() {
isLoading = false;
queryResultGigSet.add(docs.documents[i].data);
});
}
});
} else {
tempSearchGigStore = [];
queryResultGigSet.forEach((element) {
if (element['category'].startsWith(capitalizedValue)) {
setState(() {
isLoading = false;
tempSearchGigStore.add(element);
});
}
});
}
But For an array it isn't working. The code I have written is :
if (queryResultTagSet.length == 0 && val.length == 1) {
// SearchService().searchByName(val);
await databaseReference
.collection('posts')
.where('searchKeyTags', arrayContains: val.substring(0, 1).toUpperCase())
.getDocuments()
.then((QuerySnapshot docs) {
for (int i = 0; i < docs.documents.length; ++i) {
setState(() {
isLoading = false;
queryResultTagSet.add(docs.documents[i].data);
});
}
});
} else {
tempSearchTagStore = [];
queryResultTagSet.forEach((element) {
if (element['tags'].values.startsWith(capitalizedValue)) {
setState(() {
isLoading = false;
tempSearchTagStore.add(element);
});
}
});
}
}
}

the answer is
if (queryResultTagSet.length == 0 && val.length == 1) {
// SearchService().searchByName(val);
await databaseReference
.collection('posts')
.where('searchKeyTags',
arrayContains: val.substring(0, 1).toUpperCase())
.getDocuments()
.then((QuerySnapshot docs) {
for (int i = 0; i < docs.documents.length; ++i) {
setState(() {
isLoading = false;
queryResultTagSet.add(docs.documents[i].data);
});
}
});
} else {
tempSearchTagStore = [];
queryResultTagSet.forEach((element) {
List.from(element['tags']).forEach((p) {
if (p.toString().startsWith(capitalizedValue)) {
setState(() {
isLoading = false;
tempSearchTagStore.add(element);
});
}
});
});
}

Related

Pull to refresh package in flutter for pagination purpose

Hello Readers I am new in flutter and i want to do pagination, for pagination I am using one package which name is "pull to refersh".
Problems :
I have total 6 post and per page limits are 3.
1)When I reached at the end of list then api will call and set current page variable value is 2 and it will load all data of page 2 as a new list, but i want to merge page 2 data into same list... (Pagination like facebook instagram etc).
2)My another problem is when i pull for refersh, page is refersh perfectly and it will go to the first page but problem is, when i again go at the end of list it shows me no more data(which means page 2 api is not working)
I have one condition like if else:- "hasNextPage" this variable getting from api and the response is 1 or 2, if response is 1 then there further page after current page and if is 0 then there is no page after current page.
I am posting my code and api link also can you please help me.
Method for get data from API
int currentPage = 1;
bool isRefersh = false;
final RefreshController refreshController = RefreshController();
Future<UserPost> getUserPost() async {
var url =
"LINK=$currentPage";
var response = await http.get(Uri.parse(url));
var jsondata = jsonDecode(response.body.toString());
var _apiData = UserPost.fromJson(jsondata);
if (response.statusCode == 200) {
print("******getUserPost API");
print("current page****$currentPage");
print("hasnext page ${_apiData.hasNextPage}");
print(jsondata);
if(isRefersh == true){
setState((){
//currentPage = 1;
isRefersh = false;
});
refreshController.refreshCompleted();
return UserPost.fromJson(jsondata);
}
else{
print("//////////////// has next page");
print(_apiData.hasNextPage.toString());
if(_apiData.hasNextPage == 0){
refreshController.loadNoData();
return UserPost.fromJson(jsondata);
}else{
}
return UserPost.fromJson(jsondata);
}
} else {
return UserPost.fromJson(jsondata);
}
}
Method for pull to Refersh
onRefresh: () async{
await Future.delayed(Duration(milliseconds: 1000));
setState(() {
isRefersh = true;
currentPage = 1;
});
},
Method for Pagination
onLoading: () async {
if(snapshot.data!.hasNextPage == 0){
refreshController.loadNoData();
}else{
setState(() {
currentPage++;
});
await Future.delayed(Duration(milliseconds: 1000));
refreshController.loadComplete();
}
},
I Hope it's help you
try this way :-
final RefreshController refreshController =
RefreshController(initialRefresh: true);
Future<bool> getPassengerData({bool isRefresh = false}) async {
if (isRefresh) {
currentPage = 1;
} else {
if (currentPage >= totalPages) {
refreshController.loadNoData();
return false;
}
}
final Uri uri = Uri.parse(
"api url=$currentPage&size=10");
final response = await http.get(uri);
if (response.statusCode == 200) {
final result = passengersDataFromJson(response.body);
if (isRefresh) {
passengers = result.data;
}else{
passengers.addAll(result.data);
}
currentPage++;
totalPages = result.totalPages;
print(response.body);
setState(() {});
return true;
} else {
return false;
}
}
Method for pull to Refersh
onRefresh: () async {
final result = await getPassengerData(isRefresh: true);
if (result) {
refreshController.refreshCompleted();
} else {
refreshController.refreshFailed();
}
},
Method for onLoading:
onLoading: () async {
final result = await getPassengerData();
if (result) {
refreshController.loadComplete();
} else {
refreshController.loadFailed();
}
},
Try this way.
when you get the response in second page just create new list with previous list.
i.e var newData = [...?dummyData.data, ...?_apiData.data];
than return this same list.
UserPostModel dummyData = UserPostModel();
Future<UserPostModel> getUserPost() async {
var url =
"*****?page=$currentPage";
var response = await http.get(Uri.parse(url));
var jsondata = jsonDecode(response.body.toString());
var _apiData = UserPostModel.fromJson(jsondata);
var newData = [...?dummyData.data, ...?_apiData.data];
//totalPage = _apiData.totalPages as int?;
if (response.statusCode == 200) {
if (isRefersh == true) {
setState(() {
isRefersh = false;
});
refreshController.refreshCompleted();
} else {
if (_apiData.hasNextPage == 0) {
refreshController.loadNoData();
} else {
refreshController.loadComplete();
}
}
dummyData.data = newData;
return dummyData;
} else {
return dummyData;
}
}

bool value always returns true flutter

I am having trouble with the bool value. My bool value returns true only.
I have five buttons which set the state for the bool and time for fasting.
ElevatedButton(
onPressed: () async {
final SharedPreferences prefs = await _prefs;
playLocalAsset(0);
if((isFasting = true) && (widget.isFasting = true)) {
showError();
removeHours(fastDurs);
setState(() {
isFasting = false;
widget.isFasting = false;
});
//showAlerts();
} else {
setState(() {
isFasting = true;
widget.isFasting = true;
fastDuration = 16;
sixteen = 16;
eighteen = null;
twenty= null;
twentytwo = null;
twentyfour = null;
widget.fastDuration= 16;
endTime = startTime.add(Duration(hours: fastDuration!));
endTimeS = DateFormat('y/M/d, hh:mma').format(endTime);
_textLine = prefs
.setString('formattedDate', endTimeS)
.then((value) => (prefs
.getString('formattedDate') ??
Languages.of(context)!.setYourFastTime +'\n'+ startTimeS));
textDate = prefs.setString('eatTime', Languages.of(context)!.youWillEatAt)
.then((value) => (prefs.getString('eatTime') ?? ''));
showMessage(Languages.of(context)!.yourFastTimeIsSet);
updateHours(16);
});
}
},
child: Text('16:8', style: Constants.textTitleStyle),
style: Constants.buttonStyle),
const SizedBox(width:170),
ElevatedButton(
onPressed: () async {
final SharedPreferences prefs = await _prefs;
playLocalAsset(0);
if ((isFasting = true) && (widget.isFasting = true)) {
showError();
removeHours(fastDurs);
setState(() {
isFasting = false;
widget.isFasting = false;
});
//showAlerts();
} else {
setState(() {
isFasting = true;
widget.isFasting = true;
fastDuration = 18;
eighteen = 18;
sixteen = null;
twenty= null;
twentytwo = null;
twentyfour = null;
widget.fastDuration = 18;
endTime = startTime.add(Duration(hours: fastDuration!));
endTimeS = DateFormat('y/M/d, hh:mma').format(endTime);
_textLine = prefs
.setString('formattedDate', endTimeS)
.then((value) =>
(prefs
.getString('formattedDate') ??
Languages.of(context)!.setYourFastTime + '\n' + startTimeS));
textDate =
prefs.setString('eatTime', Languages.of(context)!.youWillEatAt)
.then((value) => (prefs.getString('eatTime') ?? ''));
showMessage(Languages.of(context)!.yourFastTimeIsSet);
updateHours(18);
});
}
showNotificationOneTime(context,
startTime.add(const Duration(hours: 14)).hour,
startTime.add(const Duration(minutes: 0)).minute);
showNotif(context,
endTime.hour, endTime.minute);},
child: Text('18:6', style: Constants.textTitleStyle),
style: Constants.buttonStyle
),
i declare my isFasting bool as nullable, then in init I check for the time, and if it is before the endTime then bool isFasting = true. As such:
#override
void initState() {
super.initState();
String startTimeS = DateFormat('y/M/d, hh:mma').format(startTime);
String endTimeS = DateFormat('y/M/d, hh:mma').format(endTime);
_textLine = _prefs.then((SharedPreferences prefs) {
String? fastEndTime = prefs.getString('formattedDate');
if ((fastEndTime != null) && (endTime
.isAfter(DateFormat('y/M/d, hh:mma').parse(fastEndTime)))) {
setState(() {
isFasting = false;
widget.isFasting = false;
});
return Languages.of(context)!.yourFastTimeFinished +"\n"+ endTimeS;
}
if (isFasting = false) {
return Languages.of(context)!.setYourFastTime +"\n"+ startTimeS;
}
if ((fastEndTime != null) && (endTime
.isBefore(DateFormat('y/M/d, hh:mma').parse(fastEndTime)))){
setState(() {
isFasting = true;
widget.isFasting = true;
});
}
return fastEndTime ??
Languages.of(context)!.setYourFastTime + "\n" + startTimeS;
});
textDate = _prefs.then((SharedPreferences prefs) {
String? stillFastingTime = prefs.getString('eatTime');
String? fastEndTime = prefs.getString('formattedDate');
if ((fastEndTime != null) && (endTime
.isBefore(DateFormat('y/M/d, hh:mma').parse(fastEndTime)))) {
setState(() {
isFasting = true;
widget.isFasting = true;
});
return Languages.of(context)!.youWillEatAt;
}
return stillFastingTime ?? '';
});
}
so, if isFasting is true then fast is cancelled and isFasting set to false. then clicking on a diff button should set state as shown in else condition. However, my isFasting is always true. it does not turn off... And it does not remove the previous hours, and it does not change the string of the text according to state. How do I make that bool value work properly? Thank you for your help!
use == instead of = when checking for equality:
if (isFasting = false) to if (isFasting == false)
and
if((isFasting = true) && (widget.isFasting = true)) to if(isFasting == true && widget.isFasting == true) also the braces here can be removed.
!= is correct here

Flutter QR-code scanner rapidly scan issue, how to control the second scan?

Does anyone know how to adjust the QR code scanner speed? since the second scan is so quick,
source example is down below, you can download it add and run it in your Flutter project to test!
What are the differenceis are in the controller.scannedDataStream.listen() function. I posted down below:
Barcode? result;
var qrText = "";
bool isValid = false;
bool isExpired = false;
QRViewController? controller;
controller.scannedDataStream.listen((scanData) async {
log(scanData.code);
if (!scanData.code.contains('?key=')) {
setState(() {
qrText = "This is not a correct code";
isValid = false;
});
} else {
var key_hash = scanData.code.split('?key=');
log('hash: ' + key_hash[1]);
await decrypt(key_hash[1]).then((String result) async {
if (result == "") {
log('result: ' + result);
await controller.stopCamera();
setState(() {
qrText = result;
isValid = true;
isExpired = true;
});
}
else {
log('result: ' + result);
await controller.pauseCamera();
await controller.stopCamera();
setState(() {
qrText = result;
isValid = true;
isExpired = false;
});
}
});
}
});
https://pub.dev/packages/qr_code_scanner/example

How to transform a Future method in a Stream method to feed a list

I have this method to feed my list, but with it i'm not able to change items dynamically ( add items, drop it...) :
loadLab(String submenu, [int limit]) async {
var parts = submenu.split('/');
var pathSlashless = parts[0].trim();
var subPathSlashless = parts.sublist(1).join('/').trim();
var snapshot = await _storage.ref().child("/${submenu}");
var retorno = await snapshot.listAll();
List<ItemLab> conteudo = [];
if(subPathSlashless.isEmpty || subPathSlashless == null){
retorno.prefixes.forEach((element) {
conteudo.add(
ItemLab(
tipo: 'PASTA',
elemento: element,
),
);
});
}
if(limit != null){
if(conteudo.length > limit){
hasMore = true;
return Stream.value(conteudo);
}else{
hasMore = false;
print("menor quen ove");
}
}
}
try {
if(subPathSlashless.isNotEmpty){
print(subPathSlashless);
List items;
await databaseReference
.collection("lab_${pathSlashless}_url")
.snapshots().forEach((element) {
element.docs.forEach((f) {
if(f.data()['videos'] != null){
items == null ? items = f.data()['videos'] :
items.addAll(f.data()['videos']);
};
print("ITEMS :::: >>> ${items}");
});
});
}catch(e){
print(e);
}
pathSlashless = null;
subPathSlashless = null;
conteudo = checkDuplicateFolder(conteudo, submenu);
print(conteudo);
return Stream.value(conteudo);
}
and the list>
return StreamBuilder(
stream: ctrlLab.loadLab(submenu),
throw this error:
type 'Future' is not a subtype of type 'Stream'
What I need to do to Make the return a Stream instead of a Future

issue with geting all data from sqflite database

i have been trying to get all my data from a sqflite database, when i try to get a single data, this works totally fine:
Future<dynamic> getUser() async {
final db = await database;
var res = await db.query("files");
if (res.length == 0) {
return null;
} else {
var resMap = res[0];
return resMap;
}
}
but when i try to get all data using a for loop like the example below, i get an error
Future<dynamic> getUser() async {
final db = await database;
var res = await db.query("files");
var resMap;
var count = res.length;
if (count != 0) {
for (int i = 0; i < count; i++) {
resMap.add(res[i]);
}
}
return resMap;
}
the error says:
The method 'forEach' was called on null.
Receiver: null
Tried calling: forEach(Closure: (dynamic, dynamic) => Null)
i understand that it says that I've got no data,
and i also tried to remove the if statement, but still no luck!
change this method:
EDIT
Future<List<Map>> getUser() async {
final db = await database;
var res = await db.query("files");
List<Map> resMap = [];
if (res != null res.length > 0) {
for (int i = 0; i < count; i++) {
resMap.add(res[i]);
}
return resMap;
} else
{
return null;
}
}
try this in you widget
List<Map> newUser = [];
#override
void initState() {
super.initState();
getUser();
}
getUser() async {
final _userData = await DBProvider.db.getUser();
if(_userData != null ){
setState(() {
newUser = _userData;
});
} else{
setState(() {
newUser =[];
});
}
}