MissingPluginException(No implementation found for method login on channel app.meedu/flutter_facebook_auth) - flutter-facebook-login

i got this error but not solve.i follow the step properly
this is code of my login page
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:provider/provider.dart';
class loginpage extends StatefulWidget {
const loginpage({Key? key}) : super(key: key);
#override
State<loginpage> createState() => _loginpageState();
}
enum LoginType { facebook, google, apple }
class _loginpageState extends State<loginpage> {
FirebaseAuth _auth = FirebaseAuth.instance;
bool _fetching = true;
User? get _currentUser => _auth.currentUser;
#override
void initState() {
super.initState();
_checkLogin();
}
Future<void> _checkLogin() async {
await Future.delayed(Duration(seconds: 1));
_fetching = false;
setState(() {});
}
void _login(LoginType type) async {
setState(() {
_fetching = true;
});
OAuthCredential? credential;
if (type == LoginType.facebook) {
credential = (await _loginWithFacebook()) as OAuthCredential;
} else if (type == LoginType.google) {
credential = (await _loginWithGoogle()) as OAuthCredential;
}
if (credential != null) {
await _auth.signInWithCredential(credential);
}
setState(() {
_fetching = false;
});
}
Future<OAuthCredential?> _loginWithFacebook() async {
final AccessToken accessToken = (await FacebookAuth.instance.login()) as AccessToken;
print(accessToken);
return FacebookAuthProvider.credential(
accessToken.token,
);
}
Future<OAuthCredential?> _loginWithGoogle() async {
try {
final GoogleSignInAccount? account = await GoogleSignIn(scopes: ['email']).signIn();
if (account != null) {
// Obtain the auth details from the request
final GoogleSignInAuthentication googleAuth = await account.authentication;
return GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
}
return null;
} catch (e) {
print(e);
return null;
}
}
Future<void> _logOut() async {
final List<UserInfo> data = _currentUser!.providerData;
String providerId = "firebase";
for (final item in data) {
if (item.providerId != "firebase") {
providerId = item.providerId;
break;
}
}
await _auth.signOut();
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
width: double.infinity,
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (!_fetching && _currentUser == null)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () => _login(LoginType.facebook),
child: Text("FACEBOOK"),
),
SizedBox(width: 10),
TextButton (
onPressed: () => _login(LoginType.google),
child: Text("GOOGLE"),
),
],
),
if (_fetching) CircularProgressIndicator(),
if (_currentUser != null) ...[
Text("HI ...."),
Text(_currentUser!.displayName ??" "),
SizedBox(height: 20),
TextButton(
onPressed: _logOut,
child: Text("LOG OUT"),
),
]
],
),
),
),
);
}
}
how to solve this? i follow all instruction properly.

Related

Flutter Deleting a record through the API

I am using a Laravel Api and a Flutter app as the client. This is a basic CRUD app and i was able to update the records through the API but when it comes to deleting a record, an exception is thrown and i am unable to findout the issue.
Laravel 8 App looks like this
routes\api.php
Route::apiResource('categories', \App\Http\Controllers\Api\CategoryController::class);
app\Http\Controllers\Api\CategoryController.php
public function destroy(Category $category)
{
$category->delete();
return response()->noContent();
}
Flutter App looks like this
lib\screens\categories.dart
import 'package:flutter/material.dart';
import 'package:demo_app/models/category.dart';
import 'package:demo_app/widgets/category_edit.dart';
import 'package:demo_app/providers/category_provider.dart';
import 'package:provider/provider.dart';
// import 'package:http/http.dart' as http;
class Categories extends StatefulWidget {
const Categories({super.key});
#override
CategoriesState createState() => CategoriesState();
}
class CategoriesState extends State<Categories> {
#override
Widget build(BuildContext context) {
final provider = Provider.of<CategoryProvider>(context);
List<Category> categories = provider.categories;
return Scaffold(
appBar: AppBar(
title: const Text('Categories'),
),
body: ListView.builder(
itemCount: categories.length,
itemBuilder: (context, index) {
Category category = categories[index];
return ListTile(
title: Text(category.name),
trailing:
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: const Icon(Icons.edit),
onPressed: () {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (context) {
return CategoryEdit(category, provider.updateCategory);
});
},
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () => showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('confirmation'),
content: const Text('Are you sure you want to delete?'),
actions: [
TextButton(
onPressed: () => deleteCategory(provider.deleteCategory, category),
child: const Text('Confirm')
),
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel')
),
]
);
}
),
),
],
),
);
},
)
);
}
Future deleteCategory(Function callback, Category category) async{
await callback(category);
if (!mounted) return;
Navigator.pop(context);
}
}
lib\services\api.dart
// import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:demo_app/models/category.dart';
// import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class ApiService{
ApiService();
final String baseUrl = 'http://flutter-api.test/api/';
Future<List<Category>> fetchCategories() async {
http.Response response =
await http.get(Uri.parse('${baseUrl}categories'));
List categories = jsonDecode(response.body);
return categories.map((category) => Category.fromJson(category)).toList();
}
Future <Category> updateCategory(Category category) async {
// String uri = '${baseUrl}categories/$category.id';
String uri = '${baseUrl}categories/${category.id}';
http.Response response = await http.put(Uri.parse(uri),
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
HttpHeaders.acceptHeader: 'application/json',
},
body: jsonEncode({'name': category.name}));
if(response.statusCode != 200){
throw Exception('Error happened on update');
}
return Category.fromJson(jsonDecode(response.body));
}
Future<void> deleteCategory(id) async {
String uri = '${baseUrl}categories/$id';
http.Response response = await http.delete(Uri.parse(uri));
if(response.statusCode != 204){
throw Exception('Error happened on delete');
}
}
}
lib\providers\category_provider.dart
// import 'dart:io';
import 'package:demo_app/models/category.dart';
import 'package:flutter/material.dart';
import 'package:demo_app/services/api.dart';
class CategoryEdit extends StatefulWidget {
final Category category;
final Function categoryCallback;
const CategoryEdit(this.category, this.categoryCallback, {Key? key}) : super(key: key);
#override
CategoryEditState createState() => CategoryEditState();
}
class CategoryEditState extends State<CategoryEdit> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final categoryNameController = TextEditingController();
ApiService apiService = ApiService();
String errorMessage = '';
#override
void initState(){
categoryNameController.text = widget.category.name;
super.initState();
}
#override
Widget build(BuildContext context){
return Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
key: _formKey,
child: Column(children: <Widget>[
TextFormField(
onChanged: (text) => setState(() => errorMessage = ''),
controller: categoryNameController,
validator: (String? value) {
if (value!.isEmpty) {
return 'Enter category name';
}
return null;
},
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Category Name',
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ElevatedButton(
child: const Text('Save'),
onPressed: () => saveCategory(context),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red
),
child: const Text('Cancel'),
onPressed: () => Navigator.pop(context),
),
],
),
Text(errorMessage, style: const TextStyle(color: Colors.red),)
]
)
)
);
}
Future saveCategory(BuildContext context) async {
final form = _formKey.currentState;
if(!form!.validate())
{
return;
}
widget.category.name = categoryNameController.text;
await widget.categoryCallback(widget.category);
if (!mounted) return;
Navigator.pop(context);
}
}
This is the exception i get
flutter: Exception: Error happened on delete
It returns the Error Code 500 and i was able to sort the error from the Server side

Hero animation with gallery flicker Flutter

I'm trying to create a basic Hero animation between a gallery grid view page (using photo manager plugin) and a detail page. When the hero animation is done both back and forward, the picture is flickering .
Here is the example I've made :
The full code runnable :
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:photo_manager/photo_manager.dart';
void main() {
runApp(const TestApp());
}
class TestApp extends StatefulWidget {
const TestApp({Key? key}) : super(key: key);
#override
State<TestApp> createState() => _TestAppState();
}
class _TestAppState extends State<TestApp> {
final List<AssetEntity> assetsList = [];
bool granted = false;
void loadAssets() async {
granted = await PhotoManager.requestPermission();
if (granted) {
FilterOptionGroup option = FilterOptionGroup()
..addOrderOption(const OrderOption(
type: OrderOptionType.createDate,
asc: false,
));
final albums = await PhotoManager.getAssetPathList(filterOption: option, type: RequestType.image);
print("albums : $albums");
if (albums.isNotEmpty) {
var alb = albums.where((element) {
return element.name == 'Test';
});
var album = alb.first;
// Now that we got the album, fetch all the assets it contains
List<AssetEntity> currentList =
await album.getAssetListRange(start: 0, end: 200);
// Update the state and notify UI
assetsList.clear();
assetsList.addAll(currentList);
}
setState(() {});
}
}
#override
void initState() {
loadAssets();
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: granted
? _gridView()
: Center(
child: Container(
color: Colors.blue,
width: 200,
height: 200,
child: TextButton(
onPressed: () async {
granted = await PhotoManager.requestPermission();
setState(() {});
},
child: const Text(
"Ask permission",
style: TextStyle(color: Colors.white),
),
)),
)),
);
}
Widget _gridView() {
return GridView.builder(
itemCount: assetsList.length,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (context, index) {
return Hero(
createRectTween: (Rect? begin, Rect? end) {
RectTween _rectTween = RectTween(begin: begin, end: end);
return _rectTween;
},
tag: assetsList[index].id,
child: GalleryThumbnail(
asset: assetsList[index],
onTap: (bytes) {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return DetailsPage(asset: assetsList[index], bytes: bytes);
}));
},
));
});
}
}
class GalleryThumbnail extends StatelessWidget {
final AssetEntity asset;
final ValueChanged<Uint8List> onTap;
const GalleryThumbnail({Key? key, required this.asset, required this.onTap})
: super(key: key);
#override
Widget build(BuildContext context) {
return FutureBuilder<Uint8List?>(
future: Platform.isIOS
? asset.thumbDataWithOption(
ThumbOption.ios(
width: 500,
height: 500,
deliveryMode: DeliveryMode.opportunistic,
resizeMode: ResizeMode.fast,
resizeContentMode: ResizeContentMode.fit,
quality: 100
// resizeContentMode: ResizeContentMode.fill,
),
)
: asset.thumbDataWithSize(250, 250),
builder: (_, snapshot) {
final bytes = snapshot.data;
if (snapshot.hasError) {
return Container();
}
// If we have no data
if (bytes == null) return Container();
// If there's data, display it as an image
return GestureDetector(
onTap: () {
onTap(bytes);
},
child: Image.memory(bytes, fit: BoxFit.cover,gaplessPlayback: true,));
},
);
}
}
class DetailsPage extends StatefulWidget {
final AssetEntity asset;
final Uint8List bytes;
const DetailsPage({Key? key, required this.asset, required this.bytes})
: super(key: key);
#override
_DetailsPageState createState() => _DetailsPageState();
}
class _DetailsPageState extends State<DetailsPage> {
late ImageProvider _imageProvider;
Future<void> loadFile() async {
try {
File? file = await widget.asset.file;
if (file == null) return;
_imageProvider = Image.file(file).image;
setState(() {});
} catch (e) {
print("error to load file : " + e.toString());
}
}
#override
void initState() {
_imageProvider = Image.memory(widget.bytes).image;
loadFile();
super.initState();
}
#override
Widget build(BuildContext context) {
double ratio = widget.asset.height / widget.asset.width;
return Scaffold(
body: Stack(
children: [
Hero(
createRectTween: (Rect? begin, Rect? end) {
RectTween _rectTween = RectTween(begin: begin, end: end);
return _rectTween;
},
tag: widget.asset.id,
child: Center(
child: Image(image: _imageProvider,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height*ratio,
gaplessPlayback: true),
),
),
const SafeArea(
child: Padding(
padding: EdgeInsets.all(8.0),
child: BackButton(),
)),
],
),
);
}
}
I've implemented hero animation somewhere else in my project and I'm not getting this behavior where as here I do.
Why this is happening and how to correct this ?
Add
transitionOnUserGestures: true,
to Hero() widget in current & next page
This happens because the Hero of the image thumbail wraps the FutureBuilder, and then the future triggers again during the animation, wraps the Image instead of the FutureBuilder.

How to populate JSON data when id is passed from first activity to second activities

I'm new to flutter am developing contacts app using laravel backend i have two tables which are constrained on foreign key and json response works on postman. in Flutter i have two models users model and userdetail model. users name in list view like below and works fine
class ListUsers extends StatefulWidget {
#override
_ListItemsState createState() => _ListItemsState();
}
class _ListUsersState extends State<ListUsers> {
UsersApi usersApi;
#override
void initState() {
super.initState();
usersApi = UsersApi();
usersApi.fetchAllUsers();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My Contacts'),
),
body: Container(
padding: EdgeInsets.all(16),
child:FutureBuilder(
future: itemsApi.fetchAllUsers(),
builder: (BuildContext context, AsyncSnapshot<List<Users>> snapshot)
{
switch(snapshot.connectionState)
{
case ConnectionState.active:
// working
return _loading();
break;
case ConnectionState.waiting:
//working
return _loading();
break;
case ConnectionState.none:
// no connection
return _error('No connection has been made');
break;
case ConnectionState.done:
// completed
if(snapshot.hasError)
{
return _error(snapshot.error.toString());
}
if(snapshot.hasData)
{
return _drawItemsList(snapshot.data,context);
}
break;
}
return Container();
},
),
),
);
}
Widget _drawItemsList(List<Users> myusers,BuildContext context)
{
return ListView.builder(
itemCount: myusers.length,
itemBuilder: (BuildContext context, int position){
return InkWell(
child:Card(
child:Padding(
padding: const EdgeInsets.all(8.0),
child: Text(musers[position].myuser_name),
) ,
),
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>UserDetails(muysers[position].id)));
},
);
},
);
}
Widget _loading()
{
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
Widget _error(String error)
{
return Container(
child: Center(
child: Text('Something went wrong'
),
),
);
}
}
my Api call to load listView is here also works fine
class UsersApi {
Future<List<Users>> fetchAllUsers() async //
{
String allUsers = CallApi.url + CallApi.items_url;
Map<String, String> headers =
{
'Accept': 'application/json',
};
var response = await http.get(allUsers, headers: headers);
List<Users> users = []; // its empty list we add it below
if (response.statusCode == 200) {
Map<String, dynamic> body = jsonDecode(response.body);
for (var item in body['data']) {
Users myUsers = Users.fromJson(item);
items.add(myUsers);
}
}
return users;
}
}
Now the error happens remember by passing single id from the first screen makes request of
CallApi.url+CallApi.My_Contacts+itemId;
to second screen and loads details of clicked info.
for loading other information of user from another table i created model and here is my request for second screen
class UserDetailApi {
Future<List<UserDetailModel>> fetchDetailOfSingleUser(String itemId) async
{
String userDetailUrl = CallApi.url+CallApi.My_Contacts+itemId;
Map<String,String> headers =
{
'Accept' : 'application/json',
};
var response = await http.get(userDetailUrl ,headers:headers);
List<UserDetailModel> user =[];
if(response.statusCode == 200)
{
Map<String, dynamic> body = jsonDecode(response.body);
for(var item in body['data'])
{
UserDetailModel userr = UserDetailModel.fromJson(item);
user.add(userr);
}
}
return user;
}
}
here is second activity
class UserDetails extends StatefulWidget
{
final String uId;
UserDetails(this.uId);
#override
_UserDetailsState createState()=>_UserDetailsState();
}
class _UserDetailsState extends State<UserDetails>
{
UserDetailApi itemsApi = UserDetailApi();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar:AppBar(
title:Text('Detailed Info'),
),
body: Container(
padding: EdgeInsets.all(16),
child: FutureBuilder(
future: itemsApi.fetchDetailOfSingleUser(widget.uId),
builder: (BuildContext context, AsyncSnapshot<List<UserDetailModel>> snapshot)
{
switch(snapshot.connectionState)
{
case ConnectionState.active:
// working
return _loading();
break;
case ConnectionState.waiting:
//working
return _loading();
break;
case ConnectionState.none:
// no connection
return _error('No connection has been made');
break;
case ConnectionState.done:
// completed
if(snapshot.hasError)
{
//return _error(snapshot.error.toString());
}
if(snapshot.hasData)
{
return _drawItemsList(snapshot.data);
}
break;
}
return Container();
},
),
),
);
}
Widget _drawItemsList(List<UserDetailModel> mdetail)
{
return ListView.builder(
itemCount: mdetail.length,
itemBuilder: (BuildContext context, int position){
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: mdetail.length,
itemBuilder: (BuildContext context, int position){
return InkWell(
child: Card(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(here i need to display full user info from second table),
),
),
);
},
),
);
},
);
}
Widget _loading()
{
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
Widget _error(String error)
{
return Container(
child: Center(
child: Text('Something went wrong'
),
),
);
}
}
empty screen no results populated on TextBox so please tell me where i have missed or if my works are not correct for detailed activity thanks.

Flutter Save & Load Image - Image Picker/Image crop

I'm trying to make a profile picture screen in flutter. I have used this 2 plugin (image crop and image picker) for select and edit the image.
class ProfilePage extends StatefulWidget {
#override
__ProfilePageState createState() => __ProfilePageState();
}
class __ProfilePageState extends State<ProfilePage> {
File _pickedImage;
String _imagepath;
#override
void initState() {
super.initState();
LoadImage();
}
#override
Widget build(BuildContext context) {
return Scaffold(
// appBar: AppBar(
// title: Text('Profile'),
// ),
body: ListView(
children: <Widget>[
Center(
child: CircleAvatar(
radius: 80,
child: _imagepath == null ? Text('Profile image') : null,
backgroundImage:
_imagepath != null ? FileImage(File(_imagepath)) : null,
),
),
SizedBox(height: 10),
RaisedButton(
child: Text('Select image'),
onPressed: () {
_showPickOptionDialog(context);
},
)
],
),
);
}
_loadPicker(ImageSource source) async {
File picked = await ImagePicker.pickImage(source: source);
if (picked != null) {
_cropImage(picked);
SaveImage(picked.path);
}
LoadImage();
Navigator.pop(context);
}
_cropImage(File picked) async {
File cropped = await ImageCropper.cropImage(
androidUiSettings: AndroidUiSettings(
toolbarTitle: "Modifica immagine",
statusBarColor: Colors.green,
toolbarColor: Colors.green,
toolbarWidgetColor: Colors.white,
),
sourcePath: picked.path,
// aspectRatioPresets: [
// CropAspectRatioPreset.original,
// CropAspectRatioPreset.ratio16x9,
// CropAspectRatioPreset.ratio4x3,
// ],
maxWidth: 800,
);
if (cropped != null) {
setState(() {
_pickedImage = cropped;
});
}
}
void _showPickOptionDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
title: Text('select image from gallery'),
onTap: () {
_loadPicker(ImageSource.gallery);
}),
ListTile(
title: Text('Scatta una foto'),
onTap: () {
_loadPicker(ImageSource.camera);
},
),
],
),
));
}
void SaveImage(path) async {
SharedPreferences saveimage = await SharedPreferences.getInstance();
saveimage.setString("imagepath", path);
}
void LoadImage() async {
SharedPreferences saveimage = await SharedPreferences.getInstance();
setState(() {
_imagepath = saveimage.getString("imagepath");
});
}
}
Code works but it only save the picked image instead of the cropped one.
I've tried many times but I can't see the error, sorry about that..
could you help me?
Thanks!
when you use Future you should return value and use this value with .then()
try this:
class ProfilePage extends StatefulWidget {
#override
__ProfilePageState createState() => __ProfilePageState();
}
class __ProfilePageState extends State<ProfilePage> {
File _pickedImage;
String _imagepath;
#override
void initState() {
super.initState();
LoadImage();
}
#override
Widget build(BuildContext context) {
return Scaffold(
// appBar: AppBar(
// title: Text('Profile'),
// ),
body: ListView(
children: <Widget>[
Center(
child: CircleAvatar(
radius: 80,
child: _imagepath == null ? Text('Profile image') : null,
backgroundImage:
_imagepath != null ? FileImage(File(_imagepath)) : null,
),
),
SizedBox(height: 10),
RaisedButton(
child: Text('Select image'),
onPressed: () {
_showPickOptionDialog(context);
},
)
],
),
);
}
_loadPicker(ImageSource source) async {
File picked = await ImagePicker.pickImage(source: source);
if (picked != null) {
_cropImage(picked).then(File cropped){
SaveImage(cropped.path);
}
}
LoadImage();
Navigator.pop(context);
}
Future<File> _cropImage(File picked) async {
File cropped = await ImageCropper.cropImage(
androidUiSettings: AndroidUiSettings(
toolbarTitle: "Modifica immagine",
statusBarColor: Colors.green,
toolbarColor: Colors.green,
toolbarWidgetColor: Colors.white,
),
sourcePath: picked.path,
// aspectRatioPresets: [
// CropAspectRatioPreset.original,
// CropAspectRatioPreset.ratio16x9,
// CropAspectRatioPreset.ratio4x3,
// ],
maxWidth: 800,
);
if (cropped != null) {
setState(() {
_pickedImage = cropped;
});
}
return cropped;
}
void _showPickOptionDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
title: Text('select image from gallery'),
onTap: () {
_loadPicker(ImageSource.gallery);
}),
ListTile(
title: Text('Scatta una foto'),
onTap: () {
_loadPicker(ImageSource.camera);
},
),
],
),
));
}
void SaveImage(path) async {
SharedPreferences saveimage = await SharedPreferences.getInstance();
saveimage.setString("imagepath", path);
}
void LoadImage() async {
SharedPreferences saveimage = await SharedPreferences.getInstance();
setState(() {
_imagepath = saveimage.getString("imagepath");
});
}
}
Found the solution by editing this part:
if (cropped != null) {
_pickedImage = cropped;
SaveImage(_pickedImage.path);
LoadImage();
setState(() {});
}
}

LogIn screen skipped on flutter

Currently I am designing my UI for the login screen and Firebase authentication is already in effect as I can see the username on the firebase console, however I try to edit my UI for the login screen, but the login screen is skipped and is continuously logged in, so I cannot see the changes I am making for the UI of my login screen, here is my code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'home.dart';
class Login extends StatefulWidget {
#override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
final GoogleSignIn googleSignIn = new GoogleSignIn();
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
SharedPreferences preferences;
bool loading = false;
bool isLogedin = false;
#override
void initState() {
super.initState();
isSignedIn();
}
void isSignedIn() async {
setState(() {
loading = true;
});
preferences = await SharedPreferences.getInstance();
isLogedin = await googleSignIn.isSignedIn();
if (isLogedin) {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => HomePage()));
}
setState(() {
loading = false;
});
}
Future handleSignIn() async {
preferences = await SharedPreferences.getInstance();
setState(() {
loading = true;
});
GoogleSignInAccount googleUser = await googleSignIn.signIn();
GoogleSignInAuthentication googleSignInAuthentication =
await googleUser.authentication;
AuthCredential credential = GoogleAuthProvider.getCredential(
idToken: googleSignInAuthentication.idToken,
accessToken: googleSignInAuthentication.accessToken);
FirebaseUser firebaseUser =
(await firebaseAuth.signInWithCredential(credential)).user;
if (firebaseUser != null) {
final QuerySnapshot result = await Firestore.instance
.collection("users")
.where("id", isEqualTo: firebaseUser.uid)
.getDocuments();
final List<DocumentSnapshot> documents = result.documents;
if (documents.length == 0) {
//insert the user to our collection
Firestore.instance
.collection("users")
.document(firebaseUser.uid)
.setData({
"id": firebaseUser.uid,
"username": firebaseUser.displayName,
"profilePicture": firebaseUser.photoUrl
});
await preferences.setString("id", firebaseUser.uid);
await preferences.setString("username", firebaseUser.displayName);
await preferences.setString("photUrl", firebaseUser.displayName);
} else {
await preferences.setString("id", documents[0]['id']);
await preferences.setString("username", documents[0]['username']);
await preferences.setString("photoUrl", documents[0]['photoUrl']);
}
Fluttertoast.showToast(msg: "Login was successful");
setState(() {
loading = false;
});
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => HomePage()));
} else {
Fluttertoast.showToast(msg: "Login failed :(");
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
centerTitle: true,
title: new Text(
"Login",
style: TextStyle(color: Colors.red.shade900),
),
elevation: 0.1,
),
body: Stack(children: <Widget>[
Visibility(
visible: loading ?? true,
child: Center(
child: Container(
alignment: Alignment.center,
color: Colors.white.withOpacity(0.9),
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.red),
))))
,
]),
bottomNavigationBar: Container(
child: Padding(
padding: const EdgeInsets.only(left:12.0, right: 12, top: 12, bottom: 12),
child: FlatButton(
color: Colors.red.shade900,
onPressed: () {
handleSignIn();
},
child: Text(
'Sign in/ Sign up with Google',
style: TextStyle(color: Colors.white),
)),
),
),
);
}
}
This is my code for the UI of login, however I cannot see the edits I am making on this on my emulator, as the login screen just skips (actually it appears for like 0.5 seconds and goes directly to the homepage). Could someone help me out?
You are navigating the logged-in user to the home page.
void isSignedIn() async {
setState(() {
loading = true;
});
preferences = await SharedPreferences.getInstance();
isLogedin = await googleSignIn.isSignedIn();
if (isLogedin) {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => HomePage()));
}
setState(() {
loading = false;
});
}
Either you can implement Logout in the app or just comment out the auto logged in part until your testing finish.

Resources