Refreshing Dialog In Flutter with Bloc - flutter

So I'm trying to pick a date with a DatePicker package from inside a showDialog using Bloc.
Here's the code that shows the Dialog:
onPressed: () {
showDialog(
context: context,
barrierDismissible: true,
child: _buildEditDialog(context, arguments),
);
},
And here's the Dialog's content:
void _openCalendarPicker(BuildContext context, SearchHotelArguments arguments) async {
final DateTime dateTimeNow = DateTime.now();
final List<DateTime> picked = await DateRagePicker.showDatePicker(
context: context,
initialFirstDate: arguments.checkInDate ?? dateTimeNow,
initialLastDate: arguments.checkOutDate ?? dateTimeNow.add(Duration(days: 1)),
firstDate: dateTimeNow,
lastDate: dateTimeNow.add(Duration(days: 365 * 10)));
if (picked != null && picked.length == 2) {
context.read<HotelChangeParamsBloc>().setCheckInDate(picked[0]);
context.read<HotelChangeParamsBloc>().setCheckOutDate(picked[1]);
}
}
Now, the issue here is that from a Dialog I open a popup with the DateRangePicker, pick the Date and submit it but on the Dialog the date stays the same as it was previously. And if I close and re-open the Dialog I can see that there was a change in the date. So the Dialog is not refreshing the data by itself(unless I re-open it).
Does anyone know how I can refresh the Dialog with the new Date from the DateRangePicker?

Edit:
If you're interested in adhering to the intended Bloc pattern, you wouldn't be firing a regular function from your dialog. That's why I said 'assuming you're emitting a new state'.
Ideally it would be
context.read<HotelChangeParamsBloc>().add(UserSelectedDateEvent(setCheckInDate(picked[0])));
In that example UserSelectedDateEvent is an event that passes in a DateTime object that gets emitted to an updated state.
That event would hit the mapEventToState method in your Bloc, emit a new state, and if you wrap your first dialog in a BlocBuilder as mentioned below, it will show the updated date
Original answer:
Assuming that your setCheckInDate() method is emitting a new state in your HotelChangeParamsBloc, you just need to wrap your first dialog in
BlocBuilder<HotelChangeParamsBloc, HotelChangeParamsBlocState>
Then within that, display the updated date with state.yourBlocVariable.toString()
Without the BlocBuilder theres nothing telling it to rebuild so it won't show the updated state until you close and rebuild it.

Related

ListTile not getting updated with Google Places API in flutter

I have this method which gets a suggested place through the Google Places API based on the user input.
void getSuggestion(String input) async {
var googlePlace = GooglePlace(AppConstants.APIBASE_GOOGLEMAPS_KEY);
var result = await googlePlace.queryAutocomplete.get(input);
setState(() {
_placeList = result!.predictions!;
});
}
_placeList is filled properly, but it does not get updated instantly, I have to hot reload to see the changes whenever I change the query value in my TextController:
TextField(
onSubmitted: (value) {
setState(() {
getSuggestion(value);
showDialog(
context: context,
builder: ((context) {
return Card(
child: ListTile(
title: Text(_placeList[0].description),
),
);
}));
});
},
For example, if I search for "Miami" I get the recommendation on my listTile, but if I change it to "Madrid" it still appears "Miami" and I have to reload screen to see the change.
I do not understand because I am setting the state in my method.
getSuggestion is an asynchronous function. In other words, in the following code snippet:
getSuggestion(value);
showDialog(
context: context,
...
After invoking getSuggestion, it does not wait the function to finish before showing the dialog. In other words, when the dialog is shown, maybe the previous function hasn't completed yet, so that _placeList is not updated yet.
Firstly, it is a better idea to get rid of setState within getSuggestion as it is redundant to do it twice.
Secondly, in the onSubmitted lambda, make the anonymous function async (onSubmitted: (value) async { ...), then wait for getSuggestion to finish by await getSuggestion() (do not await inside setState). At this point, _placeList is updated, and you can invoke setState now, things should rebuild properly if there are no other errors.

Is there any method that I can open an alert dialog with list of choices in flutter based on an if condition?

So basically I have a countdown timer for a minute and when the minute finishes I want an alert dialog to pop on the screen for the user e.g:
if (isCompleted) {
//open the dialog widget here
}
I can't find solutions for that. I'm only finding solutions that opens the dialog on button press.
Can anyone help?
I used this in a project of mine to display an info dialog when opening the app for the first time:
Future.delayed(Duration(milliseconds: 500), () {
showDialog(
context: context,
builder: (context) => AlertDialog(
//etc
)
You can probably wrap your widgets in a FutureBuilder (so you have access to context) with your countdown as the future argument, and, when the countdown is over, you can call showDialog from there.

Box not found. Did you forget to call Hive.openBox()? - does not detect the box even though I have opened it

I am trying to open my box after getting some data on a particular page and moving to another page. However, it keeps saying that I did not open it. Why?
GestureDetector(
onTap: () async{
final data = Hive.openBox('${setTask.getAt(index)}');
setState(() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) =>
Tasks(setTask.getAt(index), data)));
}
);
},
);
The next page
final opendata;
Tasks(#required this.opendata);
Also..I added a line in my Stateful Widget when the widget builds
final openBox = Hive.openBox('${widget.hiveName}');
Putting it in initState(){} and using async and await did not work either.
To fix you issue, you have to add await, i.e,
final data = await Hive.openBox('box');
instead of,
final data = Hive.openBox('box');
The problem here is, Flutter is rebuilding the state without waiting for Hive to actually open the box, and hence the error. Adding an await would tell Flutter to keep track of Hive opening the box and work accordingly (i.e, refresh state or whatever you want to do).

how to update the FutureBuilder text every time the shared-preference is updated

I wanted to keep the time data stored in the mobile localcaly so when ever the app is closed and open backed i want it to be shown. that part works but when ever the button is pressed to set new time it wont update to the newly set sharedprefence to show instead of the load or the new time.
This is the function that runs every time the button is being pressed
void timeInPush()async{
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
String now =await new DateFormat.yMd().add_Hm().format(new DateTime.now());
String day =await new DateFormat.d().add_Hm().format(new DateTime.now());
sharedPreferences.setString("timeIn", now);
sharedPreferences.setString("timeOut",null);
sharedPreferences.reload();
}
This is the function for the Future builder
Future <String> timeShowtimein()async{
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return Future.delayed(Duration(seconds: 1),()async{
return await sharedPreferences.getString("timeIn");
});
}
And here is the UI builder
Container timeText(){
return Container(
child:Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FutureBuilder(
future:timeShowtimein() ,
builder: (context, snapshot){
if(snapshot.hasData){
return Text("${snapshot.data}");
}else{
return Text("Loading");
}
}),
SizedBox(
width:20,
),
Text("$Timeout",style:TextStyle(
color: Colors.redAccent,
fontSize: 15.0))
],
)
);
}
Calling timeInPush() sets the values in the Shared Preferences. The problem is that it does not let the FutureBuilder know that changes have occurred.
sharedPreferences.reload() re-syncs the preferences with the native application to make sure that there are no pending changes in the dart side of things (It is stated in the documentation)
Try converting your widget to stateful and call setState(() { }) in the timeInPush() method after setting the values. This might force a rebuild and fire up the future builder again.
The problem is that it might show loading for a frame or two every time the widget rebuilds. You can fix this using initialData property = an additional variable that you might need to update manually every time you set the values in shared prefs but that will just make the code more complex. Moreover, every time you update the sharedPrefs, you will need to call setState to force the rebuild.
I will recommend rx_shared_preferences package. It's built on top of shared_preferences package and has the ability to work with streams. With StreamBuilder, you only need to update the SharedPreferences and the rebuilds inside the stream builder will be made automatically.

The method 'jumpToDay' was called on null. [Flutter]

In this application, the user will be able to add tasks and display it in a PageView.builder. The user will also be able to scroll through the PageView.builder by swiping left or right. The pageview is mapped to dates (ex: current page maps to today's date, next page maps to tomorrow's date, etc.). I also wanted to implement a jump feature which lets the user move to a new page by specifying a date on a showDatepicker widget.
The PageView.builder was implemented by using this project. this project also has the jump to page feature : https://github.com/ZedTheLed/calendar_views
the showDatepicker is implemented in the method below. it is called by clicking on a Raisedbutton:
_selectDate() async {
final DateTime picker =await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2010),
lastDate: DateTime(2040)
);
if (picker != null) {
print(picker);
return _daysPageController.jumpToDay(picker); // this method jumps the user to a selected date
// Navigator.pop(context);
// print(selectedDate);
// await runJump(selectedDate);
// return selectedDate;
}
}
when the user clicks on a date, the variable DateTime picker successfully returns the user-selected date in the print statement. But when i pass this value to the jumptopage method, it gives his error : The method 'jumpToDay' was called on null.
The PageView.builder is implemented in the code below :
final List<DateTime> days;
Scaffold(
floatingActionButton: new RaisedButton(
child: new Text("Jump To Today"),
onPressed: () {
_selectDate();
},
),
body: new Column(
children: widget.days.map(((day) => Container(
constraints: new BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 1.00,
maxWidth: MediaQuery.of(context).size.width * 1.00
),
child: Starting_screen(_makeTextString(day)), //this screen displays the tasks added by the user
)
),
).toList()
),
);
the method _makeTextString just modifies a DateTime value and returns it in a desirable format.
Could i get a suggestion on how to handle this error?
full project is available here : https://bitbucket.org/NotAnurag/todolist_restarted/src/master/
When the user clicks on a date, the variable DateTime picker successfully returns the user-selected date in the print statement. But when I pass this value to the jumptopage method, it gives his error: "The method jumpToDay was called on null"
The problem that I see in the code is that _daysPageController is not initialized. IDE helpfully suggests various methods that you can call on DaysPageController, but the fact remains that it is declared, but no value is assigned to it (meaning that it is null):
DaysPageController _daysPageController; // remains null unless assigned a value
Therefore, what the error is attempting to tell is that jumpToDay(DateTime) is called on null (which obviously does not have such a method). If you look at the stack trace a bit more explicit hint is buried in there:
[ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: The method 'jumpToDay' was called on null.
Try to initialize the controller and see if it helps to resolve the issue.