0
votes

I am building a flutter application. I want the UI part and the logical part to remain separate, so I put all my code into a separate class (that is not a widget).

My main widget file

import "package:flutter/material.dart";
import 'package:google_sign_in/google_sign_in.dart';
import 'package:appname/Models/user.dart';

final GoogleSignIn googleSignIn = GoogleSignIn();

class googleLogin extends StatefulWidget {
  @override
  _googleLoginState createState() => _googleLoginState();
}

class _googleLoginState extends State<googleLogin> {
  User user = new User();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body:Container(
        child:Column(
          children: <Widget>[
            MaterialButton(
              padding: EdgeInsets.only(top:50),
              onPressed: (){
                setState(() {
                  user.signInWithGoogle();
                });
              },
              child: Text("Log In")
            ),
            MaterialButton(
                padding: EdgeInsets.only(top:100),
                onPressed: (){
                  setState(() {
                    user.signOutWithGoogle();
                  });
                },
                child: Text("Log Out")
            ),
            if(user.username!="") Text(user.username),
            if(user.email!="")Text(user.email),
            if(user.imageurl!="") Image.network(user.imageurl),
          ],
        )
      )
    );
  }
}

My user model class

import 'dart:convert';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:appname/GoogleSignIn/GoogleSignIn.dart';
import 'package:http/http.dart' as http;

class User{
  String _username="";
  String _email="";
  String _imageurl="";

  String get imageurl=>_imageurl;
  String get email => _email;
  String get username => _username;

  Future<void> signInWithGoogle() async {
    final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
    print(googleSignInAccount.displayName);
    this._username = googleSignInAccount.displayName;
    this._email = googleSignInAccount.email;
    this._imageurl = googleSignInAccount.photoUrl;
    createUser(googleSignInAccount.displayName, googleSignInAccount.email);
    print('signInWithGoogle succeeded');
  }

  void signOutWithGoogle() async{
    await googleSignIn.signOut();
    this._username="";
    this._email = "";
    this._imageurl="";
    print("User Sign Out");
  }

  Future<http.Response> createUser(String name, String email) async {
    return http.post(
      'http://172.20.10.3:8000/createuser/',
      headers: <String, String>{
        'Content-Type': 'application/json; charset=UTF-8',
      },
      body: jsonEncode(<String, String>{
        'name':name,
        'email':email
      }),
    );
  }
}

What I expect - When the Log In button is clicked, the value of variables in the User class change. So I expect the Text widgets later in the first code file to show the user's name and email.

What happens - When I click Log In button, the value of variables is changed, but the Text fields do not change.

I have used the setState on onPressed(), so I just expect the state to be updated. Please help.

Note - I have referred to Flutter setState to another class?, Flutter: Calling SetState() from another class, Is it possible to change the state of another class using a button which is located at somewhere else in the widget tree but they do not address my problem.

1

1 Answers

0
votes

You're not awaiting any of the async functions so setState will finish before you change the value for the different variables.

It is trough the use of the await keyword that you wait for the execution of the method to end before continuing.

You need to change your code to something like this

        MaterialButton(
          padding: EdgeInsets.only(top:50),
          onPressed: () async {
            await user.signInWithGoogle();
            setState(() {});
          },
          child: Text("Log In")
        ),
        MaterialButton(
            padding: EdgeInsets.only(top:100),
            onPressed: () async {
              await user.signOutWithGoogle();
              setState(() {});
            },
            child: Text("Log Out")
        ),

And change signOutWithGoogle to return a Future

Future signOutWithGoogle() async{
   ...
}