Navigator.push is not working with setState in flutter - flutter

Navigator.push is not working with setState.
Once I removed the setState in the retry() function then it works but I want to use the setState inside the retry function.
import 'package:covid_19/screens/home.dart';
import 'package:covid_19/viewmodel/home_view_model.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyAppError());
class MyAppError extends StatefulWidget {
#override
_MyAppErrorState createState() => _MyAppErrorState();
}
class _MyAppErrorState extends State<MyAppError> {
bool _loading = false;
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return _loading ? CircularProgressIndicator() : MaterialApp(
home: Scaffold(
key: _scaffoldKey,
body: Builder(
builder:(context)=>
SafeArea(
child: Container(
margin: EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"No internet found. Check your connection",
textAlign: TextAlign.center,
),
FlatButton(
child: Text('Retry'),
onPressed: retry,
)
],
),
),
),
),
)
);
}
Future<void> retry() async{
setState(() {
_loading = true;
});
print('retrying...');
HomeViewModel homeViewModel = HomeViewModel();
homeViewModel.onAppStart().then((_){
print('pushing');
Navigator.pushReplacement(_scaffoldKey.currentContext, MaterialPageRoute(builder: (context)=> Home(data : homeViewModel.data)));
}).catchError((e){
setState(() {
_loading = false;
});
});
}
}
logs when the retry button clicked without setState:
retrying...
pushing...
and navigate to Home()
logs when the retry button clicked with setState:
retrying...
pushing...
and nothing happens

It has a logical error. when the _loading is true, there is no scaffold and you are using Scaffold key for navigating.
try this.
import 'package:covid_19/screens/home.dart';
import 'package:covid_19/viewmodel/home_view_model.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyAppError());
class MyAppError extends StatefulWidget {
#override
_MyAppErrorState createState() => _MyAppErrorState();
}
class _MyAppErrorState extends State<MyAppError> {
bool _loading = false;
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldKey,
body:_loading ? CircularProgressIndicator() : Builder(
builder:(context)=>
SafeArea(
child: Container(
margin: EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"No internet found. Check your connection",
textAlign: TextAlign.center,
),
FlatButton(
child: Text('Retry'),
onPressed: retry,
)
],
),
),
),
),
)
);
}
Future<void> retry() async{
setState(() {
_loading = true;
});
print('retrying...');
HomeViewModel homeViewModel = HomeViewModel();
homeViewModel.onAppStart().then((_){
print('pushing');
Navigator.pushReplacement(_scaffoldKey.currentContext, MaterialPageRoute(builder: (context)=> Home(data : homeViewModel.data)));
}).catchError((e){
setState(() {
_loading = false;
});
});
}
}

Related

Silent fail with flutter speech_to_text

I am trying to integrate speech to text into my flutter app. However, nothing I try is working. Here is my dart code:
import 'package:client/main.dart';
import 'package:flutter/material.dart';
import 'package:client/language/nlp.dart';
import 'package:speech_to_text/speech_recognition_result.dart';
import 'package:speech_to_text/speech_to_text.dart';
class Home extends StatefulWidget{
const Home({super.key});
#override
State<Home> createState() => HomeState();
}
class HomeState extends State<Home>{
#override
BuildContext context = navigatorKey.currentState!.context;
SpeechToText _speechToText = SpeechToText();
bool _speechEnabled = false;
String _lastWords = "";
Language nlp = Language();
#override
void initState(){
super.initState();
_initSpeech();
}
void _initSpeech() async {
_speechEnabled = await _speechToText.initialize();
setState(() {});
}
void _startListening() async {
await _speechToText.listen(onResult: _onSpeechResult);
setState(() {});
}
void _stopListening() async {
await _speechToText.stop();
setState(() {});
}
void _onSpeechResult(SpeechRecognitionResult result){
setState(() {
_lastWords = result.recognizedWords;
print(result.recognizedWords);
nlp.parseInput(result.recognizedWords);
});
}
#override
Widget build(BuildContext context){
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
padding: EdgeInsets.all(16),
child: const Text(
"Recognised words:",
style: TextStyle(fontSize: 20.0),
),
),
Expanded(
child: Container(
padding: EdgeInsets.all(16),
child: Text(
_speechToText.isListening
? '$_lastWords'
: _speechEnabled
? 'Tap the microphone to start listening...'
: "Speech not available", ),
),
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _speechToText.isNotListening ? _startListening : _stopListening,
child: Icon(_speechToText.isNotListening ? Icons.mic_off : Icons.mic),
),
);
}
}
Does anyone know of a way to make this work? No error message is being shown but the speech input is not being sent to the nlp.parseInput() function and is not being printed. I have tried googling it and can't find any solutions.

pass value between bottomNavigationBar views

How am I supposed to pass a value in this big mess called Flutter?
30 years old php global $var wasn't good?
All these years were to come up with setState, passed in a controller which get redeclared as a key inside a stateful widget that receive the value from a Navigator?
By the way, I tried using Navigator.push but it seems to open a completely new window, the value is there but I'd need it to show in the tab body not in a new window, below is my code:
main.dart
import 'dart:core';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomeView(),
);
}
}
class HomeView extends StatefulWidget {
#override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
final tabs = [QRViewExample(), SecondView(res: '')];
int _currentIndex = 0;
#override
void initState() {
setState(() {});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 40.0,
elevation: 0,
centerTitle: true,
title: Text('Flutter App'),
),
body: tabs[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.red,
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed,
selectedItemColor: Colors.white,
unselectedItemColor: Colors.white.withOpacity(0.5),
items: [
BottomNavigationBarItem(
icon: Icon(Icons.qr_code),
label: 'Scan',
),
BottomNavigationBarItem(
icon: Icon(Icons.list),
label: 'List',
),
],
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
),
);
}
}
// SECOND TAB WIDGET (custom)
class SecondView extends StatelessWidget {
const SecondView({Key? key, required this.res}) : super(key: key);
final String? res;
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text(res!),
),
);
}
}
// FIRST TAB WIDGET (qrcode)
class QRViewExample extends StatefulWidget {
const QRViewExample({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => _QRViewExampleState();
}
class _QRViewExampleState extends State<QRViewExample> {
Barcode? result;
QRViewController? controller;
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
#override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
controller!.pauseCamera();
}
controller!.resumeCamera();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: 500,
child: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Expanded(flex: 4, child: _buildQrView(context)),
Expanded(
flex: 1,
child: FittedBox(
fit: BoxFit.contain,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
if (result != null)
Text(
'Barcode Type: ${describeEnum(result!.format)} Data: ${result!.code}')
else
const Text('Scan a code'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.toggleFlash();
setState(() {});
},
child: FutureBuilder(
future: controller?.getFlashStatus(),
builder: (context, snapshot) {
return Text('Flash: ${snapshot.data}');
},
)),
),
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.flipCamera();
setState(() {});
},
child: FutureBuilder(
future: controller?.getCameraInfo(),
builder: (context, snapshot) {
if (snapshot.data != null) {
return Text(
'Camera facing ${describeEnum(snapshot.data!)}');
} else {
return const Text('loading');
}
},
)),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.pauseCamera();
},
child: const Text('pause',
style: TextStyle(fontSize: 20)),
),
),
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.resumeCamera();
},
child: const Text('resume',
style: TextStyle(fontSize: 20)),
),
)
],
),
],
),
),
)
],
),
),
),
);
}
Widget _buildQrView(BuildContext context) {
var scanArea = (MediaQuery.of(context).size.width < 400 ||
MediaQuery.of(context).size.height < 400)
? 150.0
: 300.0;
return QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderColor: Colors.cyanAccent,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutSize: scanArea),
onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
);
}
void _onQRViewCreated(QRViewController controller) {
setState(() {
this.controller = controller;
});
controller.scannedDataStream.listen((scanData) {
controller.pauseCamera();
setState(() {
result = scanData;
});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondView(res: result!.code)))
.then((value) => controller.resumeCamera());
});
}
void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) {
log('${DateTime.now().toIso8601String()}_onPermissionSet $p');
if (!p) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('no Permission')),
);
}
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
}
How am I supposed to pass a value in this big mess called Flutter?
With state management tools like InheritedWidget, InheritedModel, Provider, BloC and many more.
30 years old php global $var wasn't good? All these years were to come up with setState, passed in a controller which get redeclared as a key inside a stateful widget that receive the value from a Navigator?
Well, you shouldn't do that and it's not meant to be done like that. We can use several methods to propagate data down the widget tree. Let me explain this with InheritedWidget. But sometimes you want to go for Provider which is a wrapper class for InheritedWidget.
First we create a class named QRListModel which extends InheritedModel:
class QRListModel extends InheritedWidget {
final List<Barcode> qrList = []; // <- This holds our data
QRListModel({required super.child});
#override
bool updateShouldNotify(QRListModel oldWidget) {
return !listEquals(oldWidget.qrList, qrList);
}
static QRListModel of(BuildContext context) {
final QRListModel? result = context.dependOnInheritedWidgetOfExactType<QRListModel>();
assert(result != null, 'No QRListModel found in context');
return result!;
}
}
updateShouldNotify is a method we have to override to tell Flutter, when we want the widgets to rebuild. We want this to happen when the list changes. The of method is just a handy way to access the QRListModel.
Now wrap a parent widget of both the scan tab view and the list tab view inside QRListModel. We go for HomeView:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: QRListModel(child: HomeView()), // <- here!
);
}
}
We can take any parent widget but it should be a class where we don't call setState. Otherwise our QRListModel also gets rebuilt and our list is gone.
Now we can access QRListModel from anywhere inside the subtree. We need it here:
void _onQRViewCreated(QRViewController controller) {
setState(() {
this.controller = controller;
this.controller!.resumeCamera();
});
controller.scannedDataStream.listen((scanData) async {
controller.pauseCamera();
QRListModel.of(context).qrList.add(scanData); // <- Here we access the list
await showDialog(
context: context,
builder: (context) => SimpleDialog(
title: Text("Barcode was added!"),
children: [
Text(scanData.code!)
],
)
);
});
}
And here we read the list:
class SecondView extends StatelessWidget {
const SecondView({Key? key, required this.res}) : super(key: key);
final String? res;
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: QRListModel.of(context).qrList.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(QRListModel.of(context).qrList[index].code ?? "NO"),
),
);
}
);
}
}
Now both pages have access to the qr list. Please do mind that a InheritedWidget can only have final fields. So if you need mutable fields, you need an additional wrapper class. We don't need it as we don't change the list but only its elements.
By the way: You shouldn't call setState inside initState. You did this here:
class _HomeViewState extends State<HomeView> {
final tabs = [QRViewExample(), SecondView(res: '')];
int _currentIndex = 0;
#override
void initState() {
setState(() {}); // <- Don't call setState inside initState!
super.initState();
}

Field 'urlVar' has not been initialized. error in Flutter

I have a settings page. On this page I configure "Url". I write it down and save it. Everything is simple. But I want to make sure that the next time I visit this page I have already seen the saved Url. I download it through the shared_preferences package (where I saved it). But there was an initialization error. Someone can help me with this. So that after opening the page I saw the saved Url and could edit it.
My code
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:test/setting/сonfiguration_styles.dart';
class Setting extends StatefulWidget {
#override
_EditSettingPageState createState() => _EditSettingPageState();
}
class _EditSettingPageState extends State<Setting> {
late String urlVar;
late TextEditingController _apiController = TextEditingController();
_loadvariable() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
urlVar = (prefs.getString('apiUrl'))?? "";
});
}
#override
void initState() {
_loadvariable()?? "";
_apiController = TextEditingController( text: urlVar )
..addListener(() {
setState(() {});
});
super.initState();
}
#override
void dispose() {
_apiController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: ListView(
children: [
TextFormField(
controller: _apiController,
cursorColor: StyleSettingPage.cursorColor,
style: StyleSettingPage.textBody,
),
SizedBox(height: StyleSettingPage.heightBtwButtItem),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
onPressed: seveSettingUrl,
child: Text(
"Save",
style: StyleSettingPage.textButton
),
)
],
)
],
),
),
),
);
}
Future<void> seveSettingUrl() async {
SharedPreferences prefs = await SharedPreferences
.getInstance();
prefs.setString('apiUrl', _apiController.text);
}
}
Check this out:
First Page
import 'package:debounce/my_new_page.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class WritePage extends StatefulWidget {
const WritePage({Key? key}) : super(key: key);
#override
State<WritePage> createState() => _WritePageState();
}
class _WritePageState extends State<WritePage> {
final TextEditingController controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: ListView(
children: [
TextFormField(
controller: controller,
),
SizedBox(height: 100),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
onPressed: ()async{
SharedPreferences prefs = await SharedPreferences
.getInstance();
prefs.setString('apiUrl', controller.text);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Edit()),
);
},
child: Text(
"Save",
),
)
],
)
],
),
),
),
);
}
}
Second Page
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Edit extends StatefulWidget {
#override
_EditSettingPageState createState() => _EditSettingPageState();
}
class _EditSettingPageState extends State<Edit> {
var urlVar;
late TextEditingController _apiController = TextEditingController();
_loadvariable() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
urlVar = (prefs.getString('apiUrl'))?? "";
print("Get URL VALUE: $urlVar");
});
}
#override
void initState() {
_loadvariable();
super.initState();
}
#override
void dispose() {
_apiController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Container(
child: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: Column(
children: [TextFormField(
controller: TextEditingController( text: urlVar ),
decoration: InputDecoration(
// hintStyle: TextStyle(
// color: Colors.purple,
// fontStyle: FontStyle.italic,
// ),
),
),
SizedBox(height: 100),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
onPressed: ()async{
SharedPreferences prefs = await SharedPreferences
.getInstance();
prefs.setString('apiUrl', _apiController.text);
print("SET URL VALUE: $urlVar");
},
child: Text(
"Edit",
),
)
],
)],
)
),
),
),
);
}
}

How to get the page is not disposed

I have application which has mappage using location
class _MapPageState extends State<MapPage> {
LocationData currentLocation;
Location _locationService = new Location();
#override
void initState(){
super.initState();
_locationService.onLocationChanged().listen((LocationData result) async {
setState(() {
print(result.latitude);
print(result.longitude);
currentLocation = result;
});
});
}
In this case, setState() works well when mappage is shown.
However after mappage is disposed, there comes error like this.
E/flutter ( 6596): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
E/flutter ( 6596): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
So, I have two ideas.
Remove onLocationChanged() listener when page is disposed.
Check if State is disposed or not before setState()
How can I solve this??
You can copy paste two files below and directly replace official example's code
https://github.com/Lyokone/flutterlocation/tree/master/location/example/lib
After Navigate to ListenLocationWidget page,
you can call _stopListen() in dispose()
code snippet
class _MyHomePageState
...
RaisedButton(
child: Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<void>(
builder: (context) => ListenLocationWidget()),
);
},
),
PermissionStatusWidget(),
Divider(height: 32),
ServiceEnabledWidget(),
Divider(height: 32),
GetLocationWidget(),
Divider(height: 32),
//ListenLocationWidget()
class _ListenLocationState extends State<ListenLocationWidget> {
...
StreamSubscription<LocationData> _locationSubscription;
String _error;
#override
void initState() {
print("initState");
super.initState();
_listenLocation();
}
#override
void dispose() {
print("stopListen");
_stopListen();
super.dispose();
}
Future<void> _listenLocation() async {
_locationSubscription =
location.onLocationChanged.handleError((dynamic err) {
setState(() {
_error = err.code;
});
_locationSubscription.cancel();
}).listen((LocationData currentLocation) {
setState(() {
print("setState");
_error = null;
_location = currentLocation;
});
});
}
Future<void> _stopListen() async {
_locationSubscription.cancel();
}
working demo
full code ListenLocationWidget
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:location/location.dart';
class ListenLocationWidget extends StatefulWidget {
const ListenLocationWidget({Key key}) : super(key: key);
#override
_ListenLocationState createState() => _ListenLocationState();
}
class _ListenLocationState extends State<ListenLocationWidget> {
final Location location = Location();
LocationData _location;
StreamSubscription<LocationData> _locationSubscription;
String _error;
#override
void initState() {
print("initState");
super.initState();
_listenLocation();
}
#override
void dispose() {
print("stopListen");
_stopListen();
super.dispose();
}
Future<void> _listenLocation() async {
_locationSubscription =
location.onLocationChanged.handleError((dynamic err) {
setState(() {
_error = err.code;
});
_locationSubscription.cancel();
}).listen((LocationData currentLocation) {
setState(() {
print("setState");
_error = null;
_location = currentLocation;
});
});
}
Future<void> _stopListen() async {
_locationSubscription.cancel();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Container(
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Listen location: ' + (_error ?? '${_location ?? "unknown"}'),
style: Theme.of(context).textTheme.body2,
),
Row(
children: <Widget>[
Container(
margin: const EdgeInsets.only(right: 42),
child: RaisedButton(
child: const Text('Listen'),
onPressed: _listenLocation,
),
),
RaisedButton(
child: const Text('Stop'),
onPressed: _stopListen,
)
],
),
],
),
),
);
}
}
full code main.dart
import 'package:flutter/material.dart';
import 'package:location/location.dart';
import 'package:url_launcher/url_launcher.dart';
import 'get_location.dart';
import 'listen_location.dart';
import 'permission_status.dart';
import 'service_enabled.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Location',
theme: ThemeData(
primarySwatch: Colors.amber,
),
home: const MyHomePage(title: 'Flutter Location Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final Location location = Location();
Future<void> _showInfoDialog() {
return showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Demo Application'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
const Text('Created by Guillaume Bernos'),
InkWell(
child: Text(
'https://github.com/Lyokone/flutterlocation',
style: TextStyle(
decoration: TextDecoration.underline,
),
),
onTap: () =>
launch('https://github.com/Lyokone/flutterlocation'),
),
],
),
),
actions: <Widget>[
FlatButton(
child: const Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
IconButton(
icon: Icon(Icons.info_outline),
onPressed: _showInfoDialog,
)
],
),
body: Container(
padding: const EdgeInsets.all(32),
child: Column(
children: <Widget>[
RaisedButton(
child: Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<void>(
builder: (context) => ListenLocationWidget()),
);
},
),
PermissionStatusWidget(),
Divider(height: 32),
ServiceEnabledWidget(),
Divider(height: 32),
GetLocationWidget(),
Divider(height: 32),
//ListenLocationWidget()
],
),
),
);
}
}

How to show error when user gives wrong data in Flutter

How to show error when user can't login to system because he gives in forms bad login data(email or password)?
I would like this information to appear above email forms.
when i throw bad data in forms my response body return me in console Wrong password or User does not exists, but i want to display this information on screen
my login api:
makeLoginRequest(String email, password) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
Map data = {
'email':emailController.text,
'password':passwordController.text
};
var jsonResponse;
var url = 'http://10.0.2.2:80/user/login';
var response = await http.post(url, body:data);
if(response.statusCode == 200){
_isLoading = false;
jsonResponse = json.decode(response.body);
sharedPreferences.setInt("id", jsonResponse['id']);
sharedPreferences.setString("firstName", jsonResponse['firstName']);
sharedPreferences.setString("lastName", jsonResponse['lastName']);
setState(() {
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (BuildContext context) => Home()), (Route<dynamic> route) => false);
});
}
else{
print(response.body);
}
}
my UI:
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light
.copyWith(statusBarColor: Colors.transparent));
return Scaffold(
body: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 20.0),
child: _headerSection(),
)
],
),
Padding(
padding: EdgeInsets.all(40.0),
child: Column(
children: <Widget>[
SizedBox(height: 180.0),
_buildEmail(),
SizedBox(height: 30.0),
_buildPassword(),
SizedBox(height: 80.0),
_buttonSection(),
SizedBox(height: 40.0),
_helpText(),
],
)
)
]
)
)
),
);
}
thanks for any help :)
You can use AlertDialog yo show an error message, use the TextEditingController to pass the password if you wish. I've attached a minimalist example that you can run. The correct password would be "111" otherwise there would be an error message displayed through the ```AlertDialog````
Edit: Updated code to include snackbar instead
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final TextEditingController _controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (BuildContext context){
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _controller,
),
RaisedButton(
onPressed: () => checkPassword(context, _controller.text),
child: Text("Login",),
),
],
);
},
)
);
}
void checkPassword(BuildContext context, String password) {
if (password != "111") {
final snackBar = SnackBar(content: Text("$password is not correct!"));
Scaffold.of(context).showSnackBar(snackBar);
return;
}
print("Password corect!!");
}
}