I have a Flutter application running through VS Code which does simple authentication using Firebase. Following is my full program.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:provider/provider.dart';
import 'package:fireauth_starter/views/home_view.dart';
import 'views/login_page_view.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(FireAuthStarter());
}
class FireAuthStarter extends StatelessWidget {
//final Future<FirebaseApp> _initialisation = Firebase.initializeApp();
#override
Widget build(BuildContext context) {
//
return Provider<FirebaseAuth>(
create: (context) => FirebaseAuth.instance,
child: MaterialApp(
title: 'Firebase Authentication',
home: LandingPage(),
),
);
}
}
class LandingPage extends StatelessWidget {
const LandingPage();
#override
Widget build(BuildContext context) {
final firebaseAuth = Provider.of<FirebaseAuth>(context);
return StreamBuilder<User>(
stream: firebaseAuth.authStateChanges(),
builder: (context, AsyncSnapshot<User> snapshot) {
print(snapshot.connectionState.toString());
if (snapshot.connectionState == ConnectionState.active) {
//final bool signedIn = snapshot.hasData;
User user = snapshot.data;
return user == null ? LoginPageView() : HomeView();
//return signedIn ? DashBoard() : FirstView();
} else {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
});
}
}
class LoginPageView extends StatelessWidget {
#override
Widget build(BuildContext context) {
final firebaseAuth = Provider.of<FirebaseAuth>(context);
return MaterialApp(
home: Center(
child: Container(
child: TextButton(
child: Text('Sign In'),
onPressed: () {
firebaseAuth.signInWithEmailAndPassword(
email: 'myemail#email.com',
password: '1234567',
);
},
),
),
),
);
}
}
class HomeView extends StatelessWidget {
#override
Widget build(BuildContext context) {
final firebaseAuth = Provider.of<FirebaseAuth>(context);
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Home View'),
actions: [
TextButton(
child: Text('Sign Out'),
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all<Color>(Colors.white),
),
onPressed: () {
firebaseAuth.signOut();
},
),
],
),
body: Center(
child: Container(child: Text('Home View content')),
),
),
);
}
}
The application works as expected but when I use hot reload or hot restart, app get stuck in Progress Indicator because the snapshot.connectionState returns 'ConnectionState.waiting'
https://api.flutter.dev/flutter/widgets/ConnectionState-class.html states waiting: indicating that the asynchronous operation has begun, typically with the data being null.
I though the hot restart will reset all the states and app will perform as initial load. But it doesn't. What am I missing in this?
Related
I am working on a ecommerce-app , I'm using Getx for the state managment, I'm a newbie with Getx a little help would be appreciated.
I am using firebase auth, so when the app is navigated from the login screen everything is fine i.e products are shown,
But when when the user are kept logged in, products are not shown until hard reloaded,
main.dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp().then((value) {
Get.put(ProductsController());
});
runApp(MyApp());
}
#override
Widget build(BuildContext context) {
return MaterialApp(
routes: routes,
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
if (snapshot.hasData) {
return HomeScreen();
}
}
return const LoginScreen();
}),
);
controllers.dart
ProductsController productsController = ProductsController.instance;
home.dart
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(bottom: 20),
child: Column(
children: [
Text("Popular Products"),
PopularProducts(),
],
),
),
)
);
}
Popular Products
These products are shown only after hot reload, it is not shown initially, this is something to do with productController
class PopularProducts extends StatelessWidget {
const PopularProducts({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: SizedBox(
height: 150,
child: ListView(
scrollDirection: Axis.horizontal,
children:
productsController.products.map((ProductModel product) {
print("These are the products" + product.toString());
return ProductCard(product: product);
}).toList()),
),
)
],
);
}
The images are :
When hot restart:
When hot reload:
I faced a similar problem, my app wasn't loading the data fast enough and the widgets was already rendered, so i made a function to load the data and inside the build i used Obx() widget and called the function, but remember to but the function called with condition of the variable is empty
As #LMech replied
Obx() was missing!!
Now the code is
#override
Widget build(BuildContext context) {
return Row(
children: [
Obx( --> Add this line
() => Expanded(
child: SizedBox(
height: 150,
child: ListView(
scrollDirection: Axis.horizontal,
children:
productsController.products.map((ProductModel product) {
print("These are the products" + product.toString());
return ProductCard(product: product);
}).toList()),
),
),
)
],
);
}
On Flutter Web, the userChanges stream from a FirebaseAuth instance never emits the signed in user after a page reload. Instead, it only emits null. With the example below, the app gets stuck on the loading page.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(App());
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/loading',
onGenerateRoute: (settings) {
switch (settings.name) {
case '/error':
return MaterialPageRoute(builder: (_) => ErrorScreen());
case '/loading':
return MaterialPageRoute(builder: (_) => LoadingScreen());
case '/signin':
return MaterialPageRoute(builder: (_) => SignInScreen());
case '/welcome':
return MaterialPageRoute(builder: (_) => WelcomeScreen());
default:
return MaterialPageRoute(
builder: (_) => Center(child: Text('Unknown route')));
}
},
);
}
}
class ErrorScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Center(
child: Text('An error occurred.'),
),
);
}
}
class LoadingScreen extends StatefulWidget {
#override
_LoadingScreenState createState() => _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen> {
#override
void initState() {
init();
super.initState();
}
init() async {
try {
await Firebase.initializeApp();
if (kDebugMode) {
await FirebaseAuth.instance.useEmulator('http://localhost:1001');
}
final preferences = await SharedPreferences.getInstance();
bool signedIn = preferences.getBool('IS_SIGNED_IN') ?? false;
String landingPath = '/signin';
if (signedIn) {
landingPath = '/welcome';
// Wait for the userChanges to emit a non-null element.
await FirebaseAuth.instance
.userChanges()
.firstWhere((user) => user != null);
}
Navigator.of(context).pushReplacementNamed(landingPath);
} catch (error) {
print(error);
Navigator.of(context).pushReplacementNamed('/error');
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Center(
child: Text('Loading...'),
),
);
}
}
class SignInScreen extends StatelessWidget {
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
TextField(
controller: _emailController,
decoration: InputDecoration(labelText: 'Email address'),
),
TextField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
),
ElevatedButton(
onPressed: () => _submit(context),
child: Text('SIGN IN'),
),
],
),
),
);
}
void _submit(BuildContext context) async {
final email = _emailController.text;
final password = _passwordController.text;
FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password)
.then((credential) async {
final preferences = await SharedPreferences.getInstance();
await preferences.setBool('IS_SIGNED_IN', true);
Navigator.of(context).pushReplacementNamed('/welcome');
});
}
}
class WelcomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
Text('Welcome!'),
ElevatedButton(
onPressed: () => _signOut(context),
child: Text('SIGN OUT'),
)
],
),
),
);
}
void _signOut(BuildContext context) {
FirebaseAuth.instance.signOut().then((_) async {
final preferences = await SharedPreferences.getInstance();
await preferences.setBool('IS_SIGNED_IN', false);
Navigator.of(context).pushReplacementNamed('/signin');
});
}
}
If it helps, I'm using version 8.3.0 of the Firebase Javascript libraries in my index.html file.
Am I missing something here?
It turns out the code above is fine. The issue is the emulator. Commenting out these lines of code makes the app behave as expected:
if (kDebugMode) {
FirebaseAuth.instance.useEmulator('http://localhost:1001');
}
I've filed a bug report on FlutterFire's repo about this emulator issue.
[![enter image description here][1]][1]
I need to do it like this here:
[1]: https://i.stack.imgur.com/bNdZ3.png
But I can't do it. I tried some stuff but it doesn't work. Here is my main.dart below. I created the showImage method for showing image, I also applied it by Image.network(url); code but it didn't work,so I commented it.
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.red,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
var url;
void _incrementCounter() {
setState(() {
_counter++;
});
}
void showImage() async {
final ref = FirebaseStorage.instance.ref().child('erkekyuz');
// no need of the file extension, the name will do fine.
url = await ref.getDownloadURL();
print(url);
}
Widget _buildListItem(BuildContext context, DocumentSnapshot document) {
String mezunD;
if (document.data()['mezunDurumu'] == false) {
mezunD = "mezun değil";
}
if (document.data()['mezunDurumu'] == true) {
mezunD = "mezun değil";
}
var listTile = ListTile(
title: Column(
children: [
Expanded(
child: Text(
"Ad Soyad: " + document.data()['adSoyad'],
),
),
Expanded(
child: Text(
"Yaş: " + document.data()['yas'].toString(),
),
),
Expanded(
child: Text(
"Doğum Tarihi: " + document.data()['dogumTarihi'],
),
),
Expanded(
child: Text("Mezun Durumu: " + mezunD),
),
//Image.network(url),
//this didn't work somehow.
],
),
);
return listTile;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Öğrenci Durumu"),
),
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('tablolar').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text('Loading...');
return ListView.builder(
itemExtent: 100.0,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_buildListItem(context, snapshot.data.documents[index]),
);
}),
);
}
}
Is your url variable showing any value?
Call your showImage() method like this to load image.
#override
void initState() {
super.initState();
showImage();
}
for showing images you can use :https://pub.dev/packages/cached_network_image
I am trying to convert the boilerplate Flutter example into a web application and store the time of each click in Firestore. The program can login and the counter got incremented at each click. But it can't write to Firestore (checked via Firebase Console). Grateful if anyone can point out where I have done wrong, or pointer to the right approach. This is the code:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
#override
void _incrementCounter() {
setState(() async {
Firestore.instance.collection("click").add(
{
"time" : DateTime.now(),
});
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('DEMO')
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class AuthService {
//Handle Authentication
handleAuth() {
FirebaseAuth.instance
.signInWithEmailAndPassword(
email: 'xxxxxxxx#gmail.com', password: 'xxxxxxxx');
return StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (context, snapshot) {
if (snapshot.hasData) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyHomePage()),
);
;
} else {
return Text('Login failed');
}
},
);
}
}
I'm trying to verify the connection with Google account and Email with no success.
I'm not sure if it is a problem with versions of Dependency even though I have checked it in the net for few times or it is something with my code that isn't correct
app.gradle
implementation 'com.google.firebase:firebase-auth:19.1.0'
implementation 'com.google.android.gms:play-services-auth:17.0.0'
gradle
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.google.gms:google-services:4.3.3' // Google Services plugin
main.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:authentication/ui/home.dart';
import 'package:authentication/ui/login.dart';
import 'package:authentication/ui/splash.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 Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MainScreen(),
);
}
}
class MainScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (context,AsyncSnapshot<FirebaseUser> snapshot) {
if(snapshot.connectionState == ConnectionState.waiting)
return SplashPage();
if(!snapshot.hasData || snapshot.data == null)
return LoginPage();
return LoginPage();
},
);
}
}
firebase util
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthProvider {
final FirebaseAuth _auth = FirebaseAuth.instance;
Future<bool> signInWithEmail(String email, String password) async{
try {
AuthResult result = await _auth.signInWithEmailAndPassword(email: email,password: password);
FirebaseUser user = result.user;
if(user != null)
return true;
else
return false;
} catch (e) {
return false;
}
}
Future<void> logOut() async {
try {
await _auth.signOut();
} catch (e) {
print("error logging out");
}
}
Future<bool> loginWithGoogle() async {
try {
GoogleSignIn googleSignIn = GoogleSignIn();
GoogleSignInAccount account = await googleSignIn.signIn();
if(account == null )
return false;
AuthResult res = await _auth.signInWithCredential(GoogleAuthProvider.getCredential(
idToken: (await account.authentication).idToken,
accessToken: (await account.authentication).accessToken,
));
if(res.user == null)
return false;
return true;
} catch (e) {
print(e.toString());
return false;
}
}
}
splash
import 'package:flutter/material.dart';
class SplashPage extends StatelessWidget {
#override
Widget build(BuildContext context){
return Scaffold(
body: Container(
color: Theme.of(context).primaryColor,
child: SafeArea(
child: Container(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(
backgroundColor: Colors.white,
),
const SizedBox(height: 10.0),
Text("Loading", style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w400,
fontSize: 18.0
),),
],
),
),
),
),
);
}
}
login
import 'package:authentication/utils/firebase_auth.dart';
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
TextEditingController _emailController;
TextEditingController _passwordController;
#override
void initState() {
super.initState();
_emailController = TextEditingController(text: "");
_passwordController = TextEditingController(text: "");
}
#override
Widget build(BuildContext context){
return Scaffold(
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(height: 100.0),
Text("Login", style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20.0
),),
const SizedBox(height: 20.0),
RaisedButton(
child: Text("Login with Google"),
onPressed: () async {
bool res = await AuthProvider().loginWithGoogle();
if(!res)
print("error logging in with google");
},
),
TextField(
controller: _emailController,
decoration: InputDecoration(
hintText: "Enter email"
),
),
const SizedBox(height: 10.0),
TextField(
controller: _passwordController,
obscureText: true,
decoration: InputDecoration(
hintText: "Enter password"
),
),
const SizedBox(height: 10.0),
RaisedButton(
child: Text("Login"),
onPressed: ()async {
if(_emailController.text.isEmpty || _passwordController.text.isEmpty) {
print("Email and password cannot be empty");
return;
}
bool res = await AuthProvider().signInWithEmail(_emailController.text, _passwordController.text);
if(!res) {
print("Login failed");
}
},
)
],
),
),
),
);
}
}
home
import 'package:authentication/utils/firebase_auth.dart';
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Home page"),
RaisedButton(
child: Text("Log out"),
onPressed: (){
AuthProvider().logOut();
},
)
],
),
),
);
}
}
Log while trying to connect via email and google account
Launching lib\main.dart on Android SDK built for x86 in debug mode...
Initializing gradle...
Resolving dependencies...
Running Gradle task 'assembleDebug'...
Built build\app\outputs\apk\debug\app-debug.apk.
Installing build\app\outputs\apk\app.apk...
Syncing files to device Android SDK built for x86...
D/EGL_emulation(12507): eglMakeCurrent: 0x9d385540: ver 2 0 (tinfo 0x9d383480)
D/EGL_emulation(12507): eglMakeCurrent: 0xa67b2940: ver 2 0 (tinfo 0x86e94740)
I/zygote (12507): Do partial code cache collection, code=29KB, data=21KB
I/zygote (12507): After code cache collection, code=28KB, data=21KB
I/zygote (12507): Increasing code cache capacity to 128KB
D/EGL_emulation(12507): eglMakeCurrent: 0xa67b2940: ver 2 0 (tinfo 0x86e94740)
I/flutter (12507): PlatformException(exception, Unknown, null)
I/flutter (12507): error logging in with google
D/EGL_emulation(12507): eglMakeCurrent: 0xa67b2940: ver 2 0 (tinfo 0x86e94740)
I/zygote (12507): Do partial code cache collection, code=61KB, data=42KB
I/zygote (12507): After code cache collection, code=60KB, data=42KB
I/zygote (12507): Increasing code cache capacity to 256KB
I/BiChannelGoogleApi(12507): [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzao#d9d6493
D/FirebaseAuth(12507): Notifying id token listeners about user ( LnyMICjEyJNjtqKlCo5Qd8gAqva2 ).