Flutter and translated buttons for showAboutDialog - flutter

I have a button to display info about my app that works fine:
onTap: () async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
return showAboutDialog(
context: context,
applicationName: translate('title'),
applicationVersion: packageInfo.version,
children: [
Image(
image: AssetImage('assets/images/brand/icon.jpg'),
height: 100,
),
],
);
},
The problem is that the "View licenses" and "Close" buttons are not translated on real time. I need to refresh the whole app to get them translated:
(check that the language was updated but the buttons still not in English)
And this is the code that make the language change:
onChanged: (String newLang) async {
// update dropdown language
_language = newLang;
// update app language
changeLocale(context, newLang);
// save language
final options = json.decode(_prefs.get('options'));
options["language"] = newLang;
_prefs.setString('options', json.encode(options));
Provider.of<MyRents>(context, listen: false)
.updateLanguage(newLang);
},

The showAboutDialog() method will always display two buttons in the system's language (for you that seems to be Spanish). If you want a different behaviour, you will have to develop a custom dialog

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.

How to add back button to WebView in Flutter to dismiss the WebView altogether?

Currently when I tap on an image, it should open a web view as the image object has an associated url. I am using the url_launcher library for Flutter, and I have implemented the code as follows:
onTap: () async {
final url = image.url;
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: true,
forceWebView: true,
enableJavaScript: true,
);
}
},
My understanding is that this launches a WebView, which is an in-app browser rather than taking the user out of the app and into a separate browser app. This works fine, but the page loads much slower and Javascript elements do not work properly (e.g. animated text on websites). On the other hand,
onTap: () async {
final url = banners[index].url;
if (await canLaunch(url)) {
await launch(
url
);
}
},
works much better as it is faster and everything loads in properly, but it opens an external browser, which is not what I want.
Another issue is that I would like to add a Done button on the top left corner of the WebView to completely exit the WebView and return to where I was in the app. I only have a back button on the bottom left (on the Android emulator), that lets me go to the previous page I was at in the browser.
How do I customise the layout of the WebView, if I do not have any access to it? The url_launcher seems to handle the WebView creation internally, so I'm wondering how can I gain access from the above code to add that button?
Thank you!
If you use the native webview in this manner then you can't customise the ui. But instead, since you are displaying image you can use image.network from flutter.
Image.network(imgURL,fit: BoxFit.fill,
loadingBuilder:(BuildContext context, Widget child,ImageChunkEvent loadingProgress) {
if (loadingProgress == null)
return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null ?
loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes
: null,
),
);
},
),
Or, you can also use official webview plugin from flutter team to create in app web view.
webview_flutter: ^2.3.1
In this approaches if you add a back button in ui you can the use Navigator.pop(context); on onPressed property in button to go back

Flutter pop best practice

I have the following flow Screen 1 -> Screen 2 -> Dialog (in a separate widget).
Screen 2 displays a dialog (Close? Yes or No). If someone presses Yes, I would like to return to the Screen 1, if they press No, just close the dialog and return to Screen 2. What I currently do is when Yes is tapped, I do Navigator.pop(context) twice. Is this a good practice? Is there a way to pass the context of Screen 2 to my dialog widget so I can pop that one directly?
Personally, I think it would be better to pass the response from the dialog back to the page, and let the page handle the rest.
You can do this:
//I'm using a raised button just to call the alert as an example...
RaisedButton(
child: Text('Press me'),
//This part here is the important part
onPressed: () async {
//You can return anything when you use Navigator.pop
//In this case I'm returning a bool indicating if the page should close or not.
//You have to await this because it depends on user input.
bool shouldPopResult = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
//The content of your dialog
actions: <Widget>[
// The value you pass here in Navigator.of(context).pop
// is the value that will be stored in shouldPopResult,
// so if "Yes" is pressed, true will return...
// and if "No", false is returned.
FlatButton(
child: Text('Yes'),
onPressed: () => Navigator.of(context).pop(true),
),
FlatButton(
child: Text('No'),
onPressed: () => Navigator.of(context).pop(false),
)
],
),
);
// This is for if the user dismisses the dialog without pressing a button
// In that case shouldPopResult would be null, so I'm setting it to false.
// You can prevent the user from dismissing the dialog
// setting barrierDismissible to false in the showDialog method.
if (shouldPopResult == null) shouldPopResult = false;
// And finally with the dialog already dismissed, you can decide
// to go back or not.
if (shouldPopResult) Navigator.of(context).pop();
});
As usual you can extract the dialog as a Widget, or extract the function that handles the dialog response altogether or anything else.
You can see the example of returning data from a page in the flutter documentation here.

loading spinner with image_picker_web (FLUTTER-WEB)

How can I incorporate a loading spinner in a image_picker_web application that only triggers as an image is selected?
The best I have been able to do is a spinner triggered by the 'select image' button, as below, but this shows a spinner when the the directory is opened i.e. before anything is selected, I need it to trigger when the user selects an image and hits 'open' in the directory.
Image pickedImage;
bool isWaiting = false;
pickImage() async {
setState(() {
isWaiting = true;
});
Image fromPicker =
await ImagePickerWeb.getImage(outputType: ImageType.widget);
if (fromPicker != null) {
setState(() {
isWaiting = false;
pickedImage = fromPicker;
});
}
}
RaisedButton(
onPressed: () => pickImage(),
child: isWaiting
? SizedBox(child: Image.asset('assets/spinner.gif'))
: Text('Select Image'),
),
(adapted from the original example: https://pub.dev/packages/image_picker_web/example)
You can use the default material CircularProgressIndicator(), if you want.
If you want it a little more colorful with google color accents, you can go with my ColoredCircularProgressIndicator() package.
If you want a custom spinner then you have to definitely go with this awesome package - flutter_spinkit
Your implementation is correct, you can also use GestureDetector with Material widget for input button customizations.
EDIT -
As mentioned in comment, if you want the spinner to kick-in AFTER the image is picked, you can use then() from getImage's future and a void callback to achieve this.
Image fromPicker = await ImagePickerWeb.getImage(outputType: ImageType.widget).then(() => /* do something after image is picked (change widget to spinner in setState) */ );
I really don't know why you want to kick-in the spinner AFTER not before.
Also, image_picker_web package is now deprecated so use the image_picker package with web check.

which widget can be used to explain functionality in app

I want to explain something in my app and add a widget which looks like a notification or chat. I want this widget to be visible for some time and then get dismissed. I tried using tooltip but it is visible only when I click it.
Which widget can I use?
The Dart package intro_views_flutter is what you need, but one of its main limitations is that it is displayed on full screen, if that is not an issue to you, then you should take a look at it. Or you can use a showDialog method inside a Future function this way :
Future showNotification() async {
showDialog<String>(
context: context,
child: new AlertDialog(
title: Text('Note!') ,
contentPadding: const EdgeInsets.all(16.0),
content: //any widget you want to display here
),
);
await new Future.delayed(const Duration(seconds: 5), () {
Navigator.of(context).pop(); // this will dismiss the dialog automatically after five seconds
}
}
then when you need it call:
showNotificaion();