I have a list view with limited data and a full dialog box with full details which a user can change basically make a book request to network.As network call becomes asyn which results in pop out the dialog box earlier than changed data.
I am using Bloc Pattern and await for the network call.
new FlatButton(
child: new Text('BOOK', style: theme.textTheme.body1.copyWith(color: Colors.white)),
onPressed: () {
openShiftBloc.bookPressedSink.add(event.id);
Timer(Duration(milliseconds: 500), () => Navigator.pop(context, DismissDialogAction.cancel));
// Navigator.pop(context, DismissDialogAction.save);
}
)
Related
I am using WordPress REST API to fetch posts from a WordPress site with this piece of code with the help of wordpress_api package.
class ProvideTitle with ChangeNotifier {
List<String> Titles = [];
List<String> Descriptions = [];
List<String> Urls = [];
void ClearTitle() { //clears lists when called
Titles.clear();
Descriptions.clear();
Urls.clear();
}
void TitleFetcher(term) async { //takes term from query and adds parameters
final String searchTerm=term;
final api = WordPressAPI('https://wordpresswebsite.com');
WPResponse res = await api.posts.fetch(args: {
"search" : searchTerm,
"per_page" : "20",
"page" : "1"
});
for (final post in res.data){ //returns String to fill Lists below for each post found
Titles.add(post.title);
Descriptions.add(post.content);
Urls.add(post.link);
}
notifyListeners();
}
}
Everything is working as expected and class notifies all listeners with each List<//Strings> respectively.
Problem here is I build a list with List.generate using List<//String> Title in search bar recommendations with material_floating_search_bar, code looks like this.
class SearchPage extends StatefulWidget {
const SearchPage({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => SearchPageState();
}
class SearchPageState extends State<SearchPage> {//search bar from package mentioned
late String resultValue= "";
final controller = FloatingSearchBarController(); //controller for search bar
#override
Widget build(BuildContext context) {
return SafeArea(
child: Consumer<ProvideTitle>(builder: (context, provideTitle, child) {//Provider used for listening to ProvideTitle class
return FloatingSearchBar(
debounceDelay: const Duration(milliseconds: 165),
onQueryChanged: (query) async { //registers keyboard input
query != "" ? provideTitle.TitleFetcher(query) //sends input to TitleFetcher function inside ProvideTitle class
: provideTitle.ClearTitle(); //clears lists to stop showing fetced data with empty query(please feel free to recommend me a better way to do)
},
controller: controller,
hint: "Search",
backdropColor: Colors.transparent,
borderRadius: BorderRadius.circular(24),
physics: const BouncingScrollPhysics(),
builder: (context, _) => BuildBody(), //calls list builder as recommendations
body: resultValue != "" ? SearchResults(): //result body going to be called when some entry chosen from list
SizedBox());//page stays empty when there is no action
}),
);
}
Widget BuildBody() {
ProvideTitle model = Provider.of<ProvideTitle>(context); //ProvideTitle called for its lists as model
return ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Material(
child: Column(
children:
List.generate(model.Titles.length, (index) => model.Titles[index].toString()) //list generated as long as Title[index] which is 20 max because we only call 20 post from api
.map((e) => ListTile(
onTap: () { // i want this onTap to register which tile I chosed
model.ClearTitle();//clears lists for next search
controller.close();//closes search bar recommendations
},
title: Text(e),
))
.toList(),
),
),
);
}
}
After that list generated based on search, I want to chose one of the tiles to build a widget that contains fetched content of that post.
I created a class for contents to be displayed based on the tile we've chosen earlier but everything is also okay with that class.
How can I effectively call my class to show tiles contents that I chosen earlier, preferably without further fetching to stop wasting server resources and my devices resources.
I am completely new at flutter and developing this app for not more than three weeks without any previous coding experience other than few basic java apps that works on console, so please please please feel free to correct me in any way rather it's about my problem or not. Much thanks in advance.
Also this is my first question on here so excuse if formatting is not adequate enough for site.
Using indexOf() successfully returns the int value of chosen tile.
List.generate(model.titles.length,
(index) => model.titles[index].toString())
.map((e) => ListTile(
onTap: () {
setState(() {});
controller.close();
model.resultValue = model.titles.indexOf(e); // we are returning the int value of chosen tile to another class here
model.parsData();
model.clearFetchedData();
},
title: Text(e),
))
.toList(),
I am looking to store fetch data from firestore into a List which would contain data from all of its documents.
I defined list as :
List retrievedData = List();
next, on press of button, I wanted to print data in all documents of a specific collection. So, I did this:
RaisedButton(
onPressed: () async {
var collectionReferece = await Firestore.instance.collection('insults');
collectionReferece.getDocuments().then((collectionSnapshot){
retrievedData = collectionSnapshot.documents.toList();
});
print(retrievedData);
},
I am expecting this in console:
I/flutter (11351): [{index: 200, title: This is a test 1},{index: 100, title: This is a test 2}]
But I get this:
I/flutter (11351): [Instance of 'DocumentSnapshot', Instance of 'DocumentSnapshot']
Also, I just want to store this data in a list or any other variable. Help me out. Thank you.
Edit:
I tried to use forEach but it keeps on adding on every press of button.
If you want to:
retrieve data from firestore
add to list
create listview.builder
Then you can do the following, first declare the following variables under your State class:
class _MyHomePageState extends State<MyHomePage> {
bool isFirstTime = false;
List<DocumentSnapshot> datas = List<DocumentSnapshot>();
Next, create a method called getData() which will be referenced in onPressed:
floatingActionButton: FloatingActionButton(
onPressed: getData,
tooltip: 'Increment',
child: Icon(Icons.add),
),
getData() async {
if (!isFirstTime) {
QuerySnapshot snap =
await Firestore.instance.collection("insults").getDocuments();
isFirstTime = true;
setState(() {
datas.addAll(snap.documents);
});
}
}
Here on press of the FAB, you will get the data inside the insults collection. We use the boolean to only retrieve once per click. Inside the method dispose which you override:
#override
void dispose() {
super.dispose();
this.isFirstTime = false;
}
}
You can assign isFirstTime to false again. Then to display the data, You can use the property body of AppBar, assign it to Center widget, and the Center widget will contain the listview:
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: ListView.builder(
itemCount: datas.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('${datas[index]["index"]}'),
subtitle: Text('${datas[index]["title"]}'),
);
},
),
Using listview.builder, you will have a list in your screen and you dont have to use forEach to iterate a list. You just have to use the get operator [] to be able to get the data inside the list.
Any code that needs access to the data from Firestore, need to be inside the then. So:
var collectionReferece = await Firestore.instance.collection('insults');
collectionReferece.getDocuments().then((collectionSnapshot){
retrievedData = collectionSnapshot.documents.toList();
print(retrievedData);
});
But you'll typically want to separate the data loading out of the build() method, and use state or FutureBuilder to get the data from the database into the rendered output. Some examples of that:
Flutter/Firebase_Auth: a build function returned null for using state
How to use one field of firebase to login for another example of using state
how do i call async property in Widget build method for an example of using a FutureBuilder
i think its because the .toList() method put those 2 documents just same datatype as "DocumentSnapshot" in the List. try printing this to be sure.
print(retrievedData[0]['title']);
I have created a simple home automation project with flutter and ESP32, On my App I have a bunch of buttons that will change the state of the variables inside the firestore if they are pressed or not. If pressed send True, if not false. I'm trying to make this happen but I can't seem to get it right.
Inside the onPressed is what I have tried, all of the code is inside a Stateful class:
bool pressed = false;
Random no effect code...
CustomButton(
icon: Icons.lightbulb_outline,
text: 'On',
text2: 'Lâmpada 1\nSchuma',
onPressed: () => (){
dynamic databaseReference = Firestore.instance.collection('sensores').where('Led1','==',pressed);
Firestore.instance.runTransaction((transaction) async {
await transaction.update(
documentReference, _value);
};
},
),
SizedBox(width: 30.0),
CustomButton(
icon: Icons.lightbulb_outline,
text: 'On',
text2: 'Lâmpada 2\nSchuma',
onPressed: () => (){
},
My firestore:
Second try:
CustomButton(
icon: Icons.lightbulb_outline,
text: 'On',
text2: 'Lâmpada 1\nSchuma',
onPressed: () => (){
Firestore.instance.collection("sensores").document("2KbeT....").updateData({
'Led1': true,
});
},
),
The problem, was the button formating. The code send by Uni works great.
First add firebase to your app: https://firebase.google.com/docs/flutter/setup?platform=ios
(Import Firestore)
You can simply update your data:
Firestore.instance.collection('YourCollection').document('YourDocument').updateData({
'Led1': true,
});
To Fetch your data from the server:
await Firestore.instance
.collection('YourCollection')
.document('YourDocument')
.get()
.then((DocumentSnapshot ds) {
led1 = ds["Led1"];
led2 = ds["Led2"];
led3 = ds["Led3"];
});
I would recommend using the MQTT Protocol to communicate to your ESP32 instead of storing it in firestore. Note that firestore allows you to have 20k reads and 50k writes per day so if you have devices that need more than that it would be impractical to use firestore as a communication method.
I want to create a button with a gesture detector, and I want to listen for the second click from the user on this button.
I want to do something like this:
GestureDetector(
onSecondTap: () {
// My code
}
child: FlatButton(),
), // GestureDetector
GestureDetector has the onDoubleTap listener. This will be trigger if the user double clicks the widget within certain amount of time.
GestureDetector(
onDoubleTap: () {
// Your code here
}
...
I am trying to read data from firebase inside an AlertDialog in flutter, when a button is pressed, and then update it afterwards.
I have tried using a StreamBuilder, but nothing happens
new FlatButton(
child: const Text('+ Add'),
onPressed: () {
StreamBuilder(
stream: Firestore.instance.collection('users').document(user.uid).collection('Filtre').document('ChooseSelf').snapshots(),
builder: (context, snapshot) {
var TypeSelfFilters = snapshot.data;
List<String> ListOfTypeSelf = List.from(TypeSelfFilters["Personer"]);
ListOfTypeSelf.add("value of TextFormField");
Firestore.instance.collection('users').document(user.uid).collection('Filtre').document('ChooseSelf').updateData({'Personer': ListOfTypeSelf});
}
);
Navigator.pop(context);
}
);
I do not get any errors, but the code inside the StreamBuilder is not executed for some reason.
Thank You
Hm... It looks to me that you are expecting to get the data when the use taps on FlatButton.
Let's look what happens:
tap on FlatButton
Instantiate a StreamBuilder
Start getting data from Firestore
Do some Firestore magic, update date
Then close dialog by navigator.pop()
Problem: you call navigator.pop() right after Instantiation of StreamBuilder. StreamBuilder has to wait somewhat to get the data. If you pop a route, and with that destroying your alert dialog, the builder callback will not be called. So the actual sequence of things happening is: Tap -> Instantiate StreamBuilder -> pop route
Recommendation: why wrap your computation in a StreamBuilder? You could do:
onPressed: () {
Firestore.instance.collection('users')/*...*/.snapshots().then((snapshot) async {
// then branch is executed once snapshot is retrieved from firestore
var TypeSelfFilters = snapshot.data;
// do some more computation and magic
await Firestore.instance.collection/*...*/.updateData();
// wait for updateData to finish
Navigator.pop(context); // this context is not the context inside the StreamBuilder
});
}
Thanks to Daniel V. i found a solution:
var myData = Firestore.instance.collection('users').document(user.uid).collection('Filtre').document('ChooseSelf').snapshots().first;
myData.then((snapshot) async {
var TypeSelfFilters = snapshot.data;
List<String> ListOfTypeSelf = List.from(TypeSelfFilters["Personer"]);
ListOfTypeSelf.add("bare en test");
Firestore.instance.collection('users').document(user.uid).collection('Filtre').document('ChooseSelf').updateData({'Personer': ListOfTypeSelf});
Navigator.pop(context); // this context is not the context inside the StreamBuilder
});
}
)