How can i fix flutter app stuck in loading screen? - flutter

I'm working on a project(as a student) about writing a dictionary application. And now my code can run without an error but my app is stuck in a loading screen loop. Please help me.
ps. My English isn’t so great but I’ll try, please forgive me if I make a few mistakes
There is a problem with this area.
_search() async {
if (_controller.text == null || _controller.text.length == 0) {
_streamController.add(null);
return;
}
_streamController.add("waiting");
Uri uri = Uri.parse(_url + _controller.text.trim());
http.Response response = await http.get(uri,
headers: {"Authorization": "Token " + _token});
_streamController.add(json.decode(response.body));
}
And here is all of my code.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
//const MyApp({ Key? key }) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "FlutterDemo",
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _url = "https://owlbot.info";
String _token = "My token";
TextEditingController _controller = TextEditingController();
late StreamController _streamController;
late Stream _stream;
_search() async {
if (_controller.text == null || _controller.text.length == 0) {
_streamController.add(null);
return;
}
_streamController.add("waiting");
Uri uri = Uri.parse(_url + _controller.text.trim());
http.Response response = await http.get(uri,
headers: {"Authorization": "Token " + _token});
_streamController.add(json.decode(response.body));
}
#override
void initState() {
super.initState();
_streamController = StreamController();
_stream = _streamController.stream;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flictionary"),
bottom: PreferredSize(
preferredSize: Size.fromHeight(48.0),
child: Row(
children: <Widget>[
Expanded(
child: Container(
margin: const EdgeInsets.only(left: 12.0, bottom: 8.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24.0),
),
child: TextFormField(
onChanged: (String text) {},
controller: _controller,
decoration: InputDecoration(
hintText: "Search for a word",
contentPadding: const EdgeInsets.only(left: 24.0),
border: InputBorder.none,
),
),
),
),
IconButton(
icon: Icon(
Icons.search,
color: Colors.white,
),
onPressed: () {
_search();
},
),
],
),
),
),
body: Container(
margin: const EdgeInsets.all(8.0),
child: StreamBuilder(
stream: _stream,
builder: (BuildContext ctx, AsyncSnapshot snapshot){
if(snapshot.data == null){
return Center(
child: Text("Enter a search word"),
);
}
if(snapshot.data == "waiting"){
return Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: snapshot.data["definitions"].length,
itemBuilder: (context, int index){
return ListBody(
children: <Widget> [
Container(
color: Colors.grey[300],
child: ListTile(
leading: snapshot.data["definitions"][index]["image_url"] == null
? null:
CircleAvatar(
backgroundImage: NetworkImage(snapshot.data["definitions"][index]["image_url"]),
),
title: Text(_controller.text.trim() + "(" + snapshot.data["definitions"][index]["type"] + ")"),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(snapshot.data["definitions"][index]["definitions"]),
),
],
);
},);
},
),
),
);
}
}```

import 'dart:convert';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
//const MyApp({ Key? key }) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "FlutterDemo",
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final String _url = "https://owlbot.info/api/v4/dictionary/";
final String _token = "c7a0e47311736683d87aa05498b81862dee4f0d4";
final TextEditingController _controller = TextEditingController();
late StreamController _streamController;
late Stream _stream;
_search() async {
if (_controller.text.isEmpty) {
_streamController.add(null);
return;
}
_streamController.add("waiting");
Uri uri = Uri.parse(_url + _controller.text.trim());
http.Response response = await http.get(uri,
headers: {"Authorization": "Token " + _token});
var jsoon = json.decode(response.body);
print(jsoon["definitions"]);
_streamController.add(json.decode(response.body)["definitions"]);
}
#override
void initState() {
super.initState();
_streamController = StreamController();
_stream = _streamController.stream;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Dictionary"),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(48.0),
child: Row(
children: <Widget>[
Expanded(
child: Container(
margin: const EdgeInsets.only(left: 12.0, bottom: 8.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24.0),
),
child: TextFormField(
onChanged: (String text) {},
controller: _controller,
decoration: const InputDecoration(
hintText: "Search for a word",
contentPadding: EdgeInsets.only(left: 24.0),
border: InputBorder.none,
),
),
),
),
IconButton(
icon: const Icon(
Icons.search,
color: Colors.white,
),
onPressed: _search,
),
],
),
),
),
body: Container(
margin: const EdgeInsets.all(8.0),
child: StreamBuilder(
stream: _stream,
builder: (BuildContext ctx, AsyncSnapshot snapshot){
if(snapshot.data == null){
return const Center(
child: Text("Enter a search word"),
);
}
if(snapshot.data == "waiting"){
return const Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, int index){
print(snapshot.data.length);
return ListBody(
children: <Widget> [
Container(
color: Colors.grey[300],
child: ListTile(
leading: snapshot.data[index]["image_url"] == null
? null:
CircleAvatar(
backgroundImage: NetworkImage(snapshot.data[index]["image_url"]),
),
title: Text(_controller.text.trim() + "(" + snapshot.data[index]["definition"] + ")"),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(snapshot.data[index]["definition"]),
),
],
);
},);
},
),
),
);
}
}
You were modeling your data wrong and API used was not upto standards presented at the documentation
https://owlbot.info/api-reference#tag/English-Dictionary
Refer the link above...
This is working...
async should be imported for stream controller...
body is not required for onPressed you can directly point to the function.
unless you want to add more funtionality.

Related

Can't read the arguments on a second screen using PushNamed in Flutter

I have the following code that is passing an object as an Argument to another screen using Push named:
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter_nsd/flutter_nsd.dart';
import 'package:australremote/screens/screen5.dart';
import 'package:australremote/screens/screen6.dart';
void main() {
runApp(const Screen1());
}
class Screen1 extends StatefulWidget {
const Screen1({Key? key}) : super(key: key);
#override
State createState() => _Screen1State();
}
class _Screen1State extends State<Screen1> {
final flutterNsd = FlutterNsd();
final services = <NsdServiceInfo>[];
bool initialStart = true;
bool _scanning = false;
//List<String> _deviceIPAddresses = [];
_Screen1State();
#override
void initState() {
super.initState();
// Try one restart if initial start fails, which happens on hot-restart of
// the flutter app.
flutterNsd.stream.listen(
(NsdServiceInfo service) {
setState(() {
services.add(service);
});
},
onError: (e) async {
if (e is NsdError) {
if (e.errorCode == NsdErrorCode.startDiscoveryFailed &&
initialStart) {
await stopDiscovery();
} else if (e.errorCode == NsdErrorCode.discoveryStopped &&
initialStart) {
initialStart = false;
await startDiscovery();
}
}
},
);
startDiscovery();
}
Future<void> startDiscovery() async {
if (_scanning) return;
setState(() {
services.clear();
_scanning = true;
});
await flutterNsd.discoverServices('_http._tcp.');
/*List<InternetAddress> addresses = await services.resolve();
setState(() {
_deviceIPAddresses.add(addresses[0].address);
});*/
}
Future<void> stopDiscovery() async {
if (!_scanning) return;
setState(() {
services.clear();
_scanning = false;
});
flutterNsd.stopDiscovery();
}
#override
Widget build(BuildContext context) {
//return MaterialApp(
return Scaffold(
appBar: AppBar(
title: const Text('Your devices',style: TextStyle(color: Colors.black87),),
titleSpacing: 00.0,
centerTitle: true,
toolbarHeight: 60.2,
toolbarOpacity: 0.6,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(25),
bottomLeft: Radius.circular(25)),
),
elevation: 0.00,
backgroundColor: Colors.transparent,
),
body:
Column(
children: <Widget>[
Expanded(
child: _buildMainWidget(context),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SafeArea(
child: IconButton(
iconSize: 32.0,
icon: const Icon(Icons.add),
tooltip: 'Add a new device',
onPressed: () {
// Navigate to the second screen using a named route.
Navigator.pushNamed(context, '/second');
},
),
),
],
),
],
),
);
// );
}
Widget _buildMainWidget(BuildContext context) {
if (services.isEmpty && _scanning) {
return const Center(
child: CircularProgressIndicator(),
);
} else if (services.isEmpty && !_scanning) {
return const SizedBox.shrink();
} else {
print(services);
return ListView.builder(
itemBuilder: (context, index) => ListTile(
leading: Icon(
Icons.speaker,
color: Colors.grey[500],
),
title: Text(services[index].name ?? 'Invalid service name',textAlign: TextAlign.left,style: TextStyle(color: Colors.black,fontWeight: FontWeight.w500,
fontSize: 20,)
),
subtitle: Text(services[index].hostname ?? 'Invalid service name',textAlign: TextAlign.left,style: TextStyle(color: Colors.grey,fontWeight: FontWeight.w500,
fontSize: 10,)
),
trailing: Icon(
Icons.arrow_forward_ios,
),
onTap: ()
{
Navigator.of(context).pushNamed(
'/sixth',
arguments:services,
);
},
),
itemCount: services.length,
);
}
}
}
Second screen:
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:australremote/screens/screen1.dart';
import 'package:convert/convert.dart';
void main() {
runApp(MyHomePage6());
}
class MyHomePage6 extends StatefulWidget {
const MyHomePage6({Key? key}) : super(key: key);
#override
_MyHomePage6State createState() => _MyHomePage6State();
}
class _MyHomePage6State extends State<MyHomePage6> {
// final String args = "";
#override
Widget build(BuildContext context) {
//final services args = ModalRoute.of(context)?.settings?.arguments;
//String hostname = args[0];
final args = ModalRoute.of(context)?.settings?.arguments as List<String>;
final String services = '';
final int index;
final String hostname ='';
final String service = '';
return Scaffold(
appBar: AppBar(
title: const Text('Connect your DAC to your network',
style: TextStyle(color: Colors.black87)),
titleSpacing: 00.0,
centerTitle: true,
toolbarHeight: 60.2,
toolbarOpacity: 0.6,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(25),
bottomLeft: Radius.circular(25)),
),
elevation: 0.00,
backgroundColor: Colors.transparent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(service),
//Text("Your name is :$name"),
/*SizedBox(height: 20),
Text("HEX value: $_hexValue"),
SizedBox(height: 20),
Text("API response: $_apiResponse"),
SizedBox(height: 20),
Text("SSID Hex: $_ssidHexValue"),*/
SizedBox(height: 20),
TextButton(
onPressed:() async{
// Send an API request with the HEX value
var response = await http.get(Uri.parse(
"http://10.10.10.254/httpapi.asp?command=getStatusEx"),);
if (response.statusCode == 200) {
print(response);
// Navigator.pushNamed(context, '/');
} else {
print("There is something wrong here");
}
},
child: Text("Next", style: TextStyle(color: Colors.grey)),
),
],
),
),
);
}
}
I tried to define the getters, but I'm not quite sure I can extract the content from the arguments I've sent from the previous screen.Also, I'm receiving the following error:
type 'List' is not a subtype of type 'List' in type cast
Problem:
At first screen you defined services with generic NsdServiceInfo like:
final services = <NsdServiceInfo>[];
but on second screen , at modalRoute you used String as generic like:
final args = ModalRoute.of(context)?.settings?.arguments as List<String>;
Solution:
so make String to NsdServiceInfo in route arg defining variable like:
final args = ModalRoute.of(context)?.settings?.arguments as List<NsdServiceInfo>;

Flutter Navigator.of(context).pushNamed not passing the argument to the next screen

I have the following problem with a List Tile screen, when you select the specific Tile it should pass the arguments to the next screen, I don't know what is missing, but the navigator is not passing the arguments and it is not reporting any error either.Here is the code:
Screen 4:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:australremote/screens/screen5.dart';
void main() {
runApp(
JobsListView(),
);
}
class Job {
final String ssid;
final String auth;
final String encry;
Job({required this.ssid, required this.auth,required this.encry});
factory Job.fromJson(Map<String, dynamic> json) {
return Job(
ssid: json['ssid'],
auth: json['auth'],
encry: json['encry'],
);
}
}
class JobsListView extends StatelessWidget {
const JobsListView({Key? key}) : super(key: key);
Future<List<Job>> _fetchJobs() async {
final response = await http
.get(
Uri.parse('http://10.10.10.254/httpapi.asp?command=wlanGetApListEx'));
if (response.statusCode == 200) {
final List jsonResponse = json.decode(response.body)['aplist'] as List;
return jsonResponse.map((job) => new Job.fromJson(job)).toList();
} else {
throw Exception('Failed to load jobs from API');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Finding your available networks',
style: TextStyle(color: Colors.black87)),
titleSpacing: 00.0,
centerTitle: true,
toolbarHeight: 60.2,
toolbarOpacity: 0.6,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(25),
bottomLeft: Radius.circular(25)),
),
elevation: 0.00,
backgroundColor: Colors.transparent,
),
body: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: FutureBuilder<List<Job>>(
future: _fetchJobs(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Job> data = snapshot.data ?? [];
return _jobsListView(data);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Container(
alignment: Alignment.topCenter,
margin: EdgeInsets.only(top: 400),
child: CircularProgressIndicator(
backgroundColor: Colors.grey,
color: Colors.black,
),
);
},
),
),
],
),
),
);
}
ListView _jobsListView(data) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return _tile(
context,
title: data[index].ssid,
subtitle: data[index].auth,
icon: Icons.wifi
);
});
}
ListTile _tile(BuildContext context, {required String title,required String subtitle,required IconData icon}) =>
ListTile(
title: Text(title,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20,
)),
subtitle: Text(subtitle),
leading: Icon(
icon,
color: Colors.grey[500],
),
trailing: Icon(
Icons.arrow_forward_ios,
),
onTap: ()
{
//Navigator.pushNamed(context, '/fifth');
print(title);
print(subtitle);
Navigator.of(context).pushNamed(
'/fifth',
arguments:[title,subtitle],
);
},
//TO DO: Pass the arguments selected to the next screen, and insert it into the URI
//TO DO:Hex to ASCII.
);
}
Screen 5:
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:australremote/screens/screen4.dart';
void main() {
runApp(MyHomePage());
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _textController = TextEditingController();
final String? title = '';
final String? subtitle = '';
final String? encry= '';
#override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)?.settings?.arguments;
print(title);
print(subtitle);
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Home wifi network:$title, Authentication: $subtitle'),
TextField(
controller: _textController,
decoration: InputDecoration(hintText: "Enter the password of your Wifi network"),
),
TextButton(
style: TextButton.styleFrom(
primary: Colors.blue,
),
onPressed: () async {
// You can get the entered text using the text controller
String enteredText = _textController.text;
// Send the text to the API using the http package
final response = await http.get(Uri.parse(
"http://10.10.10.254/httpapi.asp?command=wlanConnectApEx:ssid=$title:ch=1:auth=$subtitle:encry=:pwd=$enteredText:chext=1"),
//"text=$enteredText",
);
if (response.statusCode == 200) {
Navigator.pushNamed(context, '/');
} else {
// There was an error with the request
// You can handle the error here
}
},
child: Text("Connect"),
),
],
),
),
);
}
}
I set some prints on both screen to confirm that is not passing anything to the next screen.
You can try changing this line
final args = ModalRoute.of(context)?.settings?.arguments;
to
final args = ModalRoute.of(context)?.settings?.arguments as List<String>;
or
List<String> args = ModalRoute.of(context)?.settings?.arguments;
Casting like this might solve your problem.
This is like telling Flutter that the arguments you passed is a List.
Then you can access the args like args[0] and args[1].
You are not reading the title and subtitle.
final args = ModalRoute.of(context)?.settings?.arguments;
title = args['title'];
subtitle = args['subtitle'];
print(title);
print(subtitle);

Loading different screens for different types of users in flutter

I have two types of users and I need to save the authorization session after close the app
I use Firebase and I added a bool variable to determine whether the user is "authorized" or not
When I launch the app again, I check the status.
In the code below, I can register as a "client," if the application is closed and then opened again, everything will work well
home: isLoggedIn ? const RegScreenWidget() : const StartScreenClientWidget(),
full code
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:geomap/screen/login_screen_client.dart';
import 'package:geomap/screen/logni_screen_company.dart';
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool isLoggedIn = false;
#override
void initState() {
checkStatusUser();
super.initState();
}
void checkStatusUser() {
if (FirebaseAuth.instance.currentUser == null) {
isLoggedIn = true;
} else {
isLoggedIn = false;
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Promo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.lime,
),
routes: {
'/main': (context) => const RegScreenWidget(),
'/start_screen_company': (context) => const StartScreenCompanyWidget(),
'/start_screen_client': (context) => const StartScreenClientWidget(),
},
home: isLoggedIn ? const RegScreenWidget() : const StartScreenClientWidget(),
);
}
}
class RegScreenWidget extends StatefulWidget {
const RegScreenWidget({super.key});
#override
State<RegScreenWidget> createState() => _RegScreenWidgetState();
}
class _RegScreenWidgetState extends State<RegScreenWidget> {
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Registration'),
),
body: Center(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Registration screen',
style: TextStyle(fontSize: 16),
),
const SizedBox(
height: 15,
),
Container(
width: 200,
child: Column(
children: [
TextField(
controller: _emailController,
decoration: const InputDecoration(
hintText: 'email',
border: OutlineInputBorder(),
),
),
const SizedBox(
height: 15,
),
TextField(
controller: _passController,
decoration: const InputDecoration(
hintText: 'pass',
border: OutlineInputBorder(),
),
),
],
),
),
const SizedBox(
height: 15,
),
ElevatedButton(
onPressed: regCompany,
child: const Text('Registration as a Company'),
),
const SizedBox(
height: 10,
),
ElevatedButton(
onPressed: regClient,
child: const Text('Registration as a Client'),
),
const SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("I'm already registered,"),
TextButton(
onPressed: () {},
child: Text('sign in'),
),
],
)
],
),
),
),
);
}
void regCompany() async {
var _emailCompany = _emailController.text;
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: _emailController.text.trim(),
password: _passController.text.trim(),
);
await FirebaseFirestore.instance
.collection('users')
.doc(_emailCompany)
.set({
'emailCompany': _emailCompany,
'typeUser': 'company',
});
_emailController.clear();
_passController.clear();
Navigator.of(context).pushNamed('/start_screen_company');
}
void regClient() async {
var _emailClient = _emailController.text;
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: _emailController.text.trim(),
password: _passController.text.trim(),
);
await FirebaseFirestore.instance.collection('users').doc(_emailClient).set({
'emailCompany': _emailClient,
'typeUser': 'client',
});
_emailController.clear();
_passController.clear();
Navigator.of(context).pushNamed('/start_screen_client');
}
}
But I have two types of users and I need to show two different screens. If I register as a "company," close the application, then open again, there will be an error, because I need a screen for the company.
I use the Firebase and after registration, I create a table in which the "type" of the user is displayed
image
I can check this data and use it: "client" or "company" is now authorized
How do I show different screens? I need a simple solution, I'm new and trying to understand the basic things.
My last full code, i have an error(
i think the screen loads faster than I get data on what type of user - authorized and I get an error, how i can change it?
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:geomap/screen/login_screen_client.dart';
import 'package:geomap/screen/logni_screen_company.dart';
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Map<String, Widget> screenByUser = {
'client': const StartScreenClientWidget(),
'company': const StartScreenCompanyWidget(),
};
var userType = '';
bool notLogInUser = true;
#override
void initState() {
checkStatusUser();
super.initState();
}
void checkStatusUser() async {
if (FirebaseAuth.instance.currentUser == null) {
return;
} else {
notLogInUser = false;
print('user is auth');
var _emailUser = FirebaseAuth.instance.currentUser!.email;
var document =
FirebaseFirestore.instance.collection('users').doc(_emailUser);
var snapshot = await document.get();
Map<String, dynamic>? data = snapshot.data();
var typeUserfromFBS = data!['typeUser'];
print(typeUserfromFBS);
userType = typeUserfromFBS;
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Promo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.lime,
),
routes: {
'/main': (context) => const RegScreenWidget(),
'/start_screen_company': (context) => const StartScreenCompanyWidget(),
'/start_screen_client': (context) => const StartScreenClientWidget(),
},
home: notLogInUser ? const RegScreenWidget() : screenByUser[userType],
);
}
}
class RegScreenWidget extends StatefulWidget {
const RegScreenWidget({super.key});
#override
State<RegScreenWidget> createState() => _RegScreenWidgetState();
}
class _RegScreenWidgetState extends State<RegScreenWidget> {
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Registration'),
),
body: Center(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Registration screen',
style: TextStyle(fontSize: 16),
),
const SizedBox(
height: 15,
),
Container(
width: 200,
child: Column(
children: [
TextField(
controller: _emailController,
decoration: const InputDecoration(
hintText: 'email',
border: OutlineInputBorder(),
),
),
const SizedBox(
height: 15,
),
TextField(
controller: _passController,
decoration: const InputDecoration(
hintText: 'pass',
border: OutlineInputBorder(),
),
),
],
),
),
const SizedBox(
height: 15,
),
ElevatedButton(
onPressed: regCompany,
child: const Text('Registration as a Company'),
),
const SizedBox(
height: 10,
),
ElevatedButton(
onPressed: regClient,
child: const Text('Registration as a Client'),
),
const SizedBox(
height: 10,
),
ElevatedButton(
onPressed: () {
FirebaseAuth.instance.signOut();
},
child: Text('Go Out')),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("I'm already registered,"),
TextButton(
onPressed: () {},
child: Text('sign in'),
),
],
)
],
),
),
),
);
}
void regCompany() async {
var _emailCompany = _emailController.text;
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: _emailController.text.trim(),
password: _passController.text.trim(),
);
await FirebaseFirestore.instance
.collection('users')
.doc(_emailCompany)
.set({
'emailCompany': _emailCompany,
'typeUser': 'company',
});
_emailController.clear();
_passController.clear();
Navigator.of(context).pushNamed('/start_screen_company');
}
void regClient() async {
var _emailClient = _emailController.text;
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: _emailController.text.trim(),
password: _passController.text.trim(),
);
await FirebaseFirestore.instance.collection('users').doc(_emailClient).set({
'emailCompany': _emailClient,
'typeUser': 'client',
});
_emailController.clear();
_passController.clear();
Navigator.of(context).pushNamed('/start_screen_client');
}
}
Create Map key as String (user type) and value as Widget based on user type. like below.
Map<String, Widget> screenByUser = {
'client': StartScreenClientWidget(),
'company': StartScreenCompanyWidget()
}
use below in the home
home: isLoggedIn ? const RegScreenWidget() : screenByUser['HERE_USER_TYPE'],
This might work other wise create one more screen to handle.

How to use google login in flutter and bypass emailverification

I am new to Flutter, I am currently using a logic i got from youtube to verify email first before logging in the app. The logic works just fine but now I want to make use of Google Login as an alternative.
First issue is, email address always returns null when i use google login. And i couldn't access the FirebaseAuth.instance.currentUser!.emailVerified when googleLogIn is used.
Secondly, there is no need for email verification again when using google to sign in to the app.
the App logic goes here:
Main App Page
class MyApp extends StatelessWidget {
const MyApp({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
scaffoldMessengerKey: Utils.messengerKey,
debugShowCheckedModeBanner: false,
navigatorKey: navigatorKey,
home: const AuthWrapper(),
);
}
}
class AuthWrapper extends StatelessWidget {
const AuthWrapper({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return const Center(
child: Text('Something went wrong'),
);
}
if (snapshot.hasData) {
return const VerifyEmailPage();
} else {
return const AuthPage();
}
}),
);
}
}
VerifyEmailPage
class VerifyEmailPage extends StatefulWidget {
const VerifyEmailPage({Key? key}) : super(key: key);
#override
State<VerifyEmailPage> createState() => _VerifyEmailPageState();
}
class _VerifyEmailPageState extends State<VerifyEmailPage> {
bool isEmailVerified = false;
bool canResendEmail = false;
Timer? timer;
get label => null;
#override
void initState() {
super.initState();
//user needs to be created before
isEmailVerified = FirebaseAuth.instance.currentUser!.emailVerified;
if (!isEmailVerified) {
sendVerificationEmail();
timer = Timer.periodic(
const Duration(seconds: 10),
(_) => checkEmailVerified(),
);
}
}
#override
void dispose() {
timer?.cancel();
super.dispose();
}
Future checkEmailVerified() async {
//call after email verification
await FirebaseAuth.instance.currentUser!.reload();
setState(() {
isEmailVerified = FirebaseAuth.instance.currentUser!.emailVerified;
});
if (isEmailVerified) timer?.cancel();
}
Future sendVerificationEmail() async {
try {
final user = FirebaseAuth.instance.currentUser!;
await user.sendEmailVerification();
setState(() => canResendEmail = false);
await Future.delayed(const Duration(seconds: 5));
setState(() => canResendEmail = true);
} catch (e) {
Utils.showSnackBar(e.toString());
}
}
#override
Widget build(BuildContext context) {
return isEmailVerified
? const HomeScreen()
: Scaffold(
appBar: AppBar(
backgroundColor: lightblue,
centerTitle: true,
elevation: 0,
title: const Text(
'Verify Email',
),
),
body: SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
gradient: backgroundgradient,
),
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'A verification email has been sent to your email',
style: TextStyle(fontSize: 18, color: Colors.white),
textAlign: TextAlign.center,
),
const SizedBox(
height: 20,
),
ElevatedButton.icon(
label: const Text('Resent Email'),
icon: const Icon(
Icons.email,
size: 32,
),
style: ElevatedButton.styleFrom(
minimumSize: const Size.fromHeight(50)),
onPressed:
canResendEmail ? sendVerificationEmail : null,
),
const SizedBox(
height: 8,
),
TextButton(
onPressed: () => FirebaseAuth.instance.signOut(),
child: const Text(
'Cancel',
style: TextStyle(fontSize: 14, color: Colors.white38),
),
)
],
),
),
),
));
}
}
Lastly my Google Login Button
Widget _googleSignInButton() {
return OutlinedButton.icon(
icon: Image.asset(
'assets/google_logo.png',
scale: 25,
),
label: const Text('Sign in with Google'),
onPressed: () async {
final newUser = await _googleSignIn.signIn();
final googleAuth = await newUser!.authentication;
final creds = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken, idToken: googleAuth.idToken);
await FirebaseAuth.instance.signInWithCredential(creds);
},
style: OutlinedButton.styleFrom(
minimumSize: const Size.fromHeight(50),
padding: const EdgeInsets.all(15),
elevation: 1,
primary: Colors.white54,
side: const BorderSide(
color: Colors.white30,
),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10),
),
),
),
);
}
}
I'd really appreciate an alternative or an easy work around to solve this.
Thank you in anticipation.

Call set state of FirstScreen from SecondScreen in Flutter

I have two screens in flutter named 'FirstScreen' with list of orders and 'SecondScreen' for certain actions.
I would like to call setstate of 'FirstScreen' on 'SecondScreen' pop, so that the 'FirstScreen' will reload list of pending orders
SecondScreen will accept or reject orders and it FirstScreen should reload data from server, which is called by method getOrders() in FirstScreen.
FirstScreen Code
import 'package:flutter/material.dart';
import 'package:nobleappshop/model/jobOrderItem.dart';
import 'package:nobleappshop/screens/SeconScreen.dart';
import 'package:nobleappshop/constants/constants.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class FirstScreen extends StatefulWidget {
#override
FirstScreenState createState() => FirstScreenState();
}
class FirstScreenState extends State<FirstScreen> {
Future<List<JobOrders>> _getPendingOrder() async {
var data = await http.get("$ApiServer/JobOrders/smOrdersPending");
var jsonData = json.decode(data.body);
List<JobOrders> joborderitemlist = [];
for (var i in jsonData) {
JobOrders jobOrders = JobOrders(
Eid: i["Eid"],
Uid: i["Uid"],
Name: i["Name"],
Contact: i["Contact"].toString(),
OrderStat: i["OrderStat"],
);
joborderitemlist.add(jobOrders);
}
return joborderitemlist;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('FirstScreen'),
),
body: FutureBuilder(
future: _getPendingOrder(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data.length <= 0) {
return Container(
child: Center(
child: Text('You have not made any orders yet...'),
),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return OrdersListWidget(
Eid: snapshot.data[index].Eid,
Uid: snapshot.data[index].Uid.toString(),
Name: snapshot.data[index].Name.toString(),
Contact: snapshot.data[index].Contact.toString(),
Status: snapshot.data[index].OrderStat.toString(),
);
},
);
}
} else {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
},
),
);
}
}
class OrdersListWidget extends StatelessWidget {
int Eid;
String Uid;
String Name;
String Contact;
String Status;
OrdersListWidget(
{#required this.Eid,
#required this.Uid,
#required this.Name,
#required this.Contact,
#required this.Status});
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ListTile(
leading: Text('#$Eid'),
title: Text(Name),
subtitle: Text(Contact),
trailing: Text(Status),
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: SecondScreen(OrderId: Eid),
),
),
);
},
),
Divider(),
],
);
}
}
SecondScreen Code
import 'package:flutter/material.dart';
import 'package:nobleappshop/model/orderItem.dart';
import 'package:http/http.dart' as http;
import 'package:nobleappshop/widgets/iconTextWidget.dart';
import 'package:nobleappshop/widgets/scOrderItems.dart';
import 'package:nobleappshop/constants/constants.dart';
class SecondScreen extends StatefulWidget {
int OrderId;
SecondScreen({#required this.OrderId});
#override
_SecondScreenState createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
Future<http.Response> _updateJobOrder() async {
//Run Update code here
}
double totalAmount = 0;
String token;
List<OrderItem> orderitemlist = [];
Future<List<OrderItem>> _getMyOrders() async {
//Call for orderitemslist
return orderitemlist;
}
#override
void initState() {
super.initState();
_getMyOrders();
}
#override
Widget build(BuildContext context) {
return Container(
color: Color(0xff757575),
child: Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.0),
topRight: Radius.circular(20.0),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
IconTextRowWidget(btnIcon: Icons.credit_card,btnText: 'Amount Due',btnSubText: '${totalAmount<10?10:totalAmount} QAR',),
Row(
children: <Widget>[
Expanded(
child: FlatButton(
color: Colors.green,
onPressed: (){
// Here I would like to close my current screen and reload orderslist, so that it will load all other pending joborders
_updateJobOrder();
Navigator.pop(context);
},
child: Text('Approve',style: TextStyle(color: Colors.white),),
),
),
Expanded(
child: FlatButton(
color: Colors.blueGrey,
onPressed: (){
// Here I would like to close my current screen and reload orderslist, so that it will load all other pending joborders
_updateJobOrder();
Navigator.pop(context);
},
child: Text('Reject',style: TextStyle(color: Colors.white),),
),
),
],
),
SizedBox(height: 10,)
// SizedBox(
// height: 30.0,
// ),
],
),
),
);
}
}
When I checked your code I realized that you need to send function to the grandchild of your first widget,
You need to declare a function in your OrdersListWidget because this widget is only way to access the second screen.
class OrdersListWidget extends StatelessWidget {
int Eid;
String Uid;
String Name;
String Contact;
String Status;
final VoidCallback setStateOfFirstScreen;
OrdersListWidget(
{#required this.Eid,
#required this.Uid,
#required this.Name,
#required this.Contact,
#required this.Status,
#required this.setStateOfFirstScreen});
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ListTile(
leading: Text('#$Eid'),
title: Text(Name),
subtitle: Text(Contact),
trailing: Text(Status),
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: SecondScreen(OrderId: Eid, setStateOfFirstScreen: setStateOfFirstScreen),
),
),
);
},
),
Divider(),
],
);
}
}
And send setState to the OrdersListWidget as a parameter in your first page;
ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return OrdersListWidget(
Eid: snapshot.data[index].Eid,
Uid: snapshot.data[index].Uid.toString(),
Name: snapshot.data[index].Name.toString(),
Contact: snapshot.data[index].Contact.toString(),
Status: snapshot.data[index].OrderStat.toString(),
setStateOfFirstScreen: () => setState(() {}),
);
},
);
Send the setStateOfFirstScreen to the SecondScreen and use it there to setState of the first screen;
class SecondScreen extends StatefulWidget {
final int OrderId;
final VoidCallback setStateOfFirstScreen;
SecondScreen({#required this.OrderId, #required this.setStateOfFirstScreen});
#override
_SecondScreenState createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
Future<http.Response> _updateJobOrder() async {
//Run Update code here
}
double totalAmount = 0;
String token;
List<OrderItem> orderitemlist = [];
Future<List<OrderItem>> _getMyOrders() async {
//Call for orderitemslist
return orderitemlist;
}
#override
void initState() {
super.initState();
_getMyOrders();
}
#override
Widget build(BuildContext context) {
return Container(
color: Color(0xff757575),
child: Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.0),
topRight: Radius.circular(20.0),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
IconTextRowWidget(
btnIcon: Icons.credit_card,
btnText: 'Amount Due',
btnSubText: '${totalAmount < 10 ? 10 : totalAmount} QAR',
),
Row(
children: <Widget>[
Expanded(
child: FlatButton(
color: Colors.green,
onPressed: () {
// Here I would like to close my current screen and reload orderslist, so that it will load all other pending joborders
_updateJobOrder();
Navigator.pop(context);
widget.setStateOfFirstScreen();
},
child: Text(
'Approve',
style: TextStyle(color: Colors.white),
),
),
),
Expanded(
child: FlatButton(
color: Colors.blueGrey,
onPressed: () {
// Here I would like to close my current screen and reload orderslist, so that it will load all other pending joborders
_updateJobOrder();
Navigator.pop(context);
widget.setStateOfFirstScreen();
},
child: Text(
'Reject',
style: TextStyle(color: Colors.white),
),
),
),
],
),
SizedBox(
height: 10,
)
// SizedBox(
// height: 30.0,
// ),
],
),
),
);
}
}
You can declare a void call back or a function as a property of second screen and send it from first screen; here is an example;
class SecondScreen extends StatelessWidget {
final VoidCallback setStateOfFirstScreen;
const SecondScreen({Key key, this.setStateOfFirstScreen}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(icon: Icon(Icons.refresh), onPressed: setStateOfFirstScreen),
],
),
body: Center(),
);
}
}
class FistScreen extends StatefulWidget {
#override
_FistScreenState createState() => _FistScreenState();
}
class _FistScreenState extends State<FistScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: FlatButton(
child: Text("Go to the second screen"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (c) => SecondScreen(
setStateOfFirstScreen: () => setState(() {}),
),
),
);
},
),
),
);
}
}