Showing recently search in dropdown field - flutter

I have created an auto complete drop down field which shows data of api and when i search particular data i have saved data into sharedpreference also so that i can show few recently searched list so to achieve that i checked a condition saying if textformcontroller value is empty meaning nothing is types in textform field show recently search drop down and if someone type something in textform field then soo filtred data which come from api.
This is my code
optionsViewBuilder: (BuildContext context,
AutocompleteOnSelected<Result1> onSelected,
Iterable<Result1> options) {
if (fieldTextEditingController.value.text == "") {
return Align(
alignment: Alignment.topLeft,
child: Material(
child: Container(
width: 0.78.w(context),
color: Colors.white,
child: ListView.builder(
padding: const EdgeInsets.all(10.0),
itemCount: titles.length,
itemBuilder:
(BuildContext context, int index) {
final Result1 option =
options.elementAt(index);
return GestureDetector(
onTap: () {
onSelected(option);
},
child: ListTile(
title: Text(titles[index],
style: const TextStyle(
color: Colors.black87)),
trailing: InkWell(
onTap: () {
titles.removeAt(index);
},
child: Text("X")),
),
);
},
),
),
),
);
} else {
return Align(
alignment: Alignment.topLeft,
child: Material(
child: Container(
width: 0.78.w(context),
color: Colors.white,
child: ListView.builder(
padding: const EdgeInsets.all(10.0),
itemCount: options.length,
itemBuilder:
(BuildContext context, int index) {
final Result1 option =
options.elementAt(index);
return GestureDetector(
onTap: () {
onSelected(option);
},
child: ListTile(
title: Text(option.originalTitle!,
style: const TextStyle(
color: Colors.black87)),
),
);
},
),
),
),
);
}
},
inside optionviewbuilder i want am checking if fieldTextEditingController is empty then show data from sharedpreference if not show data from api but data only renders of sharedpreference not from api need some guidance here i am stuck

what we can do is declare an string variable and inside textformfield it has property saying onChanged which takes value just assign that value to your declared string variable and use that declared variable to check if that variable is empty show shared preference data else show api data
eg:- String? data;
onChanged:(value){
data = value
}
then,
if(data == null || data.isEmpty){
show shared preference data
}else{
show apidata
}

Related

Update item widget from local database list

I'm using a ready-made local database in my application and the problem is that I can't update one item from the list. If I add a chapter to favorites, then the button's state is updated only after the page is reopened. Likewise, the favorites list is updated only when the page is reopened. Right now when I add/remove favorites, I dynamically load the entire list so that it updates the values, but I only need to update one item, how can I do this using a provider? I didn’t give code examples, because I want to understand exactly the logic of actions
UPD:
My code:
#override
Widget build(BuildContext context) {
return FutureBuilder<List>(
future: _databaseQuery.getAllChapters(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
return snapshot.connectionState == ConnectionState.done &&
snapshot.hasData
? CupertinoScrollbar(
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, int index) {
return MainChapterItem(
item: snapshot.data![index],
);
},
),
)
: const Center(
child: CircularProgressIndicator.adaptive(),
);
},
);
}
Item:
final MainChapterItemModel item;
#override
Widget build(BuildContext context) {
return Material(
child: InkWell(
child: Container(
padding: const EdgeInsets.all(8),
child: Row(
children: [
IconButton(
icon: item.favoriteState == 0
? const Icon(CupertinoIcons.bookmark)
: const Icon(CupertinoIcons.bookmark_fill),
splashRadius: 22,
splashColor: const Color(0xff81b9b0),
onPressed: () {
context.read<BookmarkButtonState>().addRemoveChapterBookmark(
item.favoriteState == 0 ? 1 : 0, item.id);
},
),
const SizedBox(
width: 8,
),
Flexible(
child: ListTile(
contentPadding: EdgeInsets.zero,
title: Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Text(
item.chapterNumber,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
subtitle: Html(
data: item.chapterTitle,
style: {
'#': Style(
fontSize: const FontSize(17),
padding: EdgeInsets.zero,
margin: EdgeInsets.zero,
),
'small': Style(
fontSize: const FontSize(8),
),
'a': Style(
fontSize: const FontSize(14),
color: Colors.blue,
),
},
),
),
),
],
),
),
onTap: () {},
),
);
}
The problem is that when I add to favorites or delete, the button state is not updated. And in the favorites list, the item is not deleted on click, but it disappears after the page is reopened:
IconButton(
icon: item.favoriteState == 0
? const Icon(CupertinoIcons.bookmark)
: const Icon(CupertinoIcons.bookmark_fill),
splashRadius: 22,
splashColor: const Color(0xff81b9b0),
onPressed: () {
context.read<BookmarkButtonState>().addRemoveChapterBookmark(
item.favoriteState == 0 ? 1 : 0, item.id);
},
),
Provider code:
final DatabaseQuery _databaseQuery = DatabaseQuery();
DatabaseQuery get getDatabaseQuery => _databaseQuery;
addRemoveChapterBookmark(int state, int chapterId) {
_databaseQuery.addRemoveFavoriteChapter(state, chapterId);
notifyListeners();
I solved the problem by signing all lists to listen to databaseQuery in the provider:
future: context.watch<BookmarkButtonState>().getDatabaseQuery.getAllChapters(),

How to update the ui when my list gets filled with data GetX Flutter

Im trying to show a listView.builder inside a AlertDialog, and Im filling the its list by calling a function everytime the button to open the AlertDialog is pressed but the problem is that the ui doesn’t update when the list is filled with the data, I'm using getX and I'm very new to it, can someone show me what I'm doing wrong?
I'm using the GetX builder:
GetX<DashboardController>(
init: Get.put<DashboardController>(DashboardController()),
builder: (DashboardController dashboardController) {
return GridView.builder(
My Get.dialog function:
return GestureDetector(
onTap: () {
// this is where I'm filling the list
dashboardController
.callEmployeeCheckInOutList(_employeeModel.id);
Get.dialog(
AlertDialog(
contentPadding: EdgeInsets.zero,
content: SizedBox(
height: size.height * 0.55,
width: size.width,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
EmployeeProfileWidget(
size: size,
profileBackgroudPath: profileBackgroudPath,
employeeModel: _employeeModel,
),
// this is where my listview.builder resides
EmployeeActivityWidget(
closeCrossPath: closeCrossPath,
employeeCheckInOutList:
_employeeCheckInOutList,
employeeModel: _employeeModel,
onTap: () {},
),
],
),
),
),
);
},
My listview.builder:
Expanded(
child: Padding(
padding: const EdgeInsets.only(
left: 32.0,
right: 50.0,
),
child: ListView.builder(
itemCount: employeeCheckInOutList.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final _checkInOutModel = employeeCheckInOutList[index];
return SizedBox(
height: 120,
child: TimelineTile(
beforeLineStyle: const LineStyle(
color: Color(0xffa5affb),
),
My Controller:
Rx<List<CheckInOutModel>> _employeeCheckInOutList =
Rx<List<CheckInOutModel>>([]);
List<CheckInOutModel> get employeeCheckInOutList =>
_employeeCheckInOutList.value;
Future<void> callEmployeeCheckInOutList(String id) async {
_employeeCheckInOutList =
await EmployeeService.employeeCheckInOutFuture(docId: id);
update();
}
Use .assignAll method on the RxList to trigger UI update:
Future<void> callEmployeeCheckInOutList(String id) async {
final result = await EmployeeService.employeeCheckInOutFuture(docId: id);
_employeeCheckInOutList.assignAll(result);
}
And you don't need to call update() when using Rx.
I already faced same issue.
Solution:
Simply use again GetX<Controller> inside AlertDialog
like
GetX<DashboardController>(
init: Get.put<DashboardController>(DashboardController()),
builder: (DashboardController dashboardController) {
return GridView.builder(
.....
Get.dialog(
AlertDialog(
contentPadding: EdgeInsets.zero,
content: GetX<DashboardController>(
init: Get.put<DashboardController>(DashboardController()),
builder: (DashboardController dashboardController) {
SizedBox(

Type 'Future<dynamic>' is not subtype of type 'Widget'

I am showing markers from API on google maps. Here is my build method. When the program reaches the _widgetbuilder() method, it throws the specific error of type Future is not a subtype of the widget. If someone could please help to solve the problem and also tell me that what exactly this error means.....
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: FutureBuilder<List<MarkersOnMap>>(
future: future,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData)
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
if (snapshot.hasData && snapshot.data.isEmpty) {
return Center(
child: Container(
child: Column(
children: [
Text(
'No Properties Added Yet\nPlease Add Some!',
style:
TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
ElevatedButton.icon(
onPressed: () {
Navigator.push(
context,
PageTransition(
duration: Duration(microseconds: 500),
type: PageTransitionType.fade,
child: AddNewEproperty(
createEproperty: widget.createEproperty),
),
);
},
label: Text('Add'),
icon: Icon(Icons.add),
),
],
),
),
);
} else
_widgetbuilder();
if (snapshot.hasData) {
return ListView.builder(
itemCount: allWidgets.length + 1,
shrinkWrap: true,
padding: EdgeInsets.only(top: 16),
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, i) {
return Stack(
children: <Widget>[
Container(),],);},);},},),);}
This is the _widgetbuilder() method. When it reaches this return _widgetbuilder, throws _typeerror.
_widgetbuilder() async {
allWidgets = [];
widget.markersonmap = await future;
widget.markersonmap.forEach(
(element) {
print(element);
allWidgets.add(
Container(
height: 25,
width: 50,
child: new DecoratedBox(
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
borderRadius: BorderRadius.circular(5.0),
color: Colors.black54),
child: Text(
element.ePropertiesCardsList.price.toString(),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
),
);
},
);
}
You are getting this error because your function _widgetbuilder returns Future<dynamic> because the function is async.
Widget _widgetbuilder(){
// code here
}
The function should be in this structure to return of type Widget. The code that needs to be async should either be taken out of build function or use .then pattern for async code instead of async await if you really need to.
This short 9 min video will help you understand async better in flutter.
In here now the type error is solved but after reading 'future.then..... it does not goto the future and fetch data but jumps to the next foreach line and then calls it as null.
_widgetbuilder() {
allWidgets = [];
// widget.markersonmap = await future;
future.then((value) {
widget.markersonmap = value;
});
widget.markersonmap.forEach(
(element) {
print(element);
allWidgets.add(
Container(
// other code
}

How to display something while the value is null/loading in Flutter?

I've created a real-time object detection with Tiny YOLOv2 using Flutter app. So far the app managed to detect the object and display its bounding box with the detectedClass and confidence. Then I pulled the detectedClass (the name of the object) and assigned it into my String _result variable because I need it to fetch data from Firebase later.
The main issue is when the app is not detecting anything I want to display something like maybe 'Loading...' until the _result return the name of the object bcus u see my custom Tiny YOLOv2 takes a lil bit of time before it detect the object. Then, I want to fetch data based on _result from the Firebase. So far, I've managed to fetch the data from the Firebase BUT ONLY if I hardcoded the name of the object detected. Otherwise the app would return null error if I'm fetching using _result variable.
Below is my attempt of displaying the the name of the food and its calorie (which is fetched from the Firebase) based on the _result variable but FAILED:
return MaterialApp(
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image:AssetImage('assets/back.jpg'), fit: BoxFit.fill),
),
child: Column(
children: [
Stack(
children: [
Center(
child: Container(
margin: EdgeInsets.only(top: 10),
// child: Icon(Icons.photo_camera, color: Colors.orange, size: 40),
child: Text('Press on the camera icon',
style: TextStyle(
fontSize: 16.0,
color: Colors.orangeAccent,
fontWeight: FontWeight.bold
),
textAlign: TextAlign.center,
),
),
),
Center(
child: FlatButton(
onPressed: ()
{
initCamera();
},
child: Container(
margin: EdgeInsets.only(top: 35),
height: 270,
width: 360,
color: Colors.orange,
child: Stack(
children: list,
),
),
),
),
],
),
Center(
child: Container(
margin: EdgeInsets.only(top: 45.0),
child: SingleChildScrollView(
child: FutureBuilder(
future: dbRef.orderByChild("food_name").equalTo(_result).once(),
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(
child: Text("Loading..."),
);
} else {
lists.clear();
Map<dynamic, dynamic> values = snapshot.data.value;
values.forEach((key, values) {
lists.add(values);
});
return ListView.builder(
shrinkWrap: true,
itemCount: lists.length,
itemBuilder: (BuildContext context,
int index) {
return
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment
.start,
children: <Widget>[
Text("Name: " + lists[index]["food_name"]),
Text("Calorie: " + lists[index]["calorie"]),
],
),
);
});
}
})
),
),
),
],
),
),
),
),
);
}
}
The error from the above is:
Exception has occurred.
NoSuchMethodError (NoSuchMethodError: The method 'forEach' was called on null.
Receiver: null
Tried calling: forEach(Closure: (String, dynamic) => Null))
My issue is kinda similar with this user and the solution in there is not working in my case.
I dont know whether its possible to fetch the data from firebase based on the real time input? Otherwise how do I save the name of the object somewhere to make it static(?) I'm really new to Flutter so some guidance on how to code it is very much appreciated. Thank you in advance.
Edited Btw just want to add it here. This is how I declared my _result:
_recognitions.forEach((response)
{
_result = "${response["detectedClass"]}" + "\n\n";
});
Basically _result is just the name of the object detected.
Just wanna share how I resolved this in case anyone's having the same issue. All I did is just insert a while (values == null) inside my else statement like this:
else {
values = snapshot.data.value;
while (values == null){
return Center(
child: CircularProgressIndicator(color: Colors.orange),
);
}
lists.clear();
values.forEach((key, values){
lists.add(values);
});
}
and then followed by the ListView.builder() to display them.
Btw, thank you so much for those who responded!

How to print the value without selecting the index in Choice Chip in Flutter

I am using chips_choice library and also fetching the api data, then this api data is displaying on chips_choice which is displaying is "Apple" & "Banana" and by default first index is selected that is "Apple". So my question is by default first index is selected how can i print that already selected index without clicking or selecting it manually? Below is the sample dart code.
String specialRequest = "";
Row(
children: [
GestureDetector(
onTap: (){
print(specialRequest); // I want to print "Apple" without selecting or clicking manually .
},
child: Text('What is the occasion')),
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Container(
width: MediaQuery.of(context).size.width * 0.45,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: data.data!.occassions!.length,
itemBuilder: (BuildContext context, int index) {
return ChoiceChip(
label: Text(data.data!.occassions![index]!.name!), // Api data displaying is "Apple" "Banana"
selected: occasionIndex == index,
selectedColor: TuxedoColor.redColor,
onSelected: (bool selected) {
specialRequest = data.data!.occassions![index]!.id!;
setState(() {
occasionIndex = selected ? index : 0;
});
},
backgroundColor: Colors.white,
labelStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold),
);
}),
),
)
],
),
If I understand well, you want to print the value or the index.
Change this:
itemBuilder: (BuildContext context, int index) {
return ChoiceChip(
To this:
itemBuilder: (BuildContext context, int index) {
specialRequest = data.data!.occassions![index]!.id!; //***New Line ***
print(specialRequest);
return ChoiceChip(
Let me know if you meant something else