Home > OS >  Flutter: How to Call a Function that is in a Stateful Widgets State Class, that depends on the initS
Flutter: How to Call a Function that is in a Stateful Widgets State Class, that depends on the initS

Time:12-22

I am unsure if this question has been asked before, but I was unable to find an answer to it.

I have a stateful widget for my signin page, which uses the flutter_toast package for error handling (incorrect password, email already in use, etc.). When using flutter_toast, in order to make a custom toast, I have to use the initState function of the signin page. I also have another class, in a separate file, in which I am trying to move all of my Firebase Auth services into (this is where I am needing to call the showToast function, which is declared in the SigninState class). I have been having trouble figuring out how to get the showToast function to be defined in the AuthService class, so that I will be able to call it there.

Here is my Signin stateful widget class:

class Signin extends StatefulWidget {
  const Signin({Key? key}) : super(key: key);

  @override
  _SigninState createState() => _SigninState();
}

class _SigninState extends State<Signin> {
  FToast? fToast;
  AuthService authService = AuthService();

  @override
  void initState() {
    super.initState();
    fToast = FToast();
    fToast!.init(context);
  }
...
// build function{
//   in here, I call "authService.signInAction()", which needs to call "showToast()"
// }
...
}
showToast(String msg, context) {
    bool smallPhone = false;
    double width = MediaQuery.of(context).size.width;
    if (width <= 370) smallPhone = true;
    Widget toast = Container(
      padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(25.0),
        color: Colors.redAccent,
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          const SizedBox(
            width: 10.0,
          ),
          Text(
            msg,
            style:
                TextStyle(fontSize: smallPhone ? 13 : 15, color: Colors.white),
          ),
        ],
      ),
    );

    fToast!.showToast(
      child: toast,
      gravity: ToastGravity.CENTER,
      toastDuration: const Duration(seconds: 2),
    );
  }
...
...
} // closing tag for _SigninState class

Here is my AuthService class:

class AuthService {
  FirebaseAuth auth = FirebaseAuth.instance;
  Signin signin = const Signin();

  UserModel _userFromFirebaseUser(User user) {
    return UserModel(id: user.uid);
  }

  Stream<UserModel> get user {
    return auth.authStateChanges().map((user) => _userFromFirebaseUser(user!));
  }

  Future signInAction(
      String email, String password, BuildContext context) async {
    try {
      User user = (await auth.signInWithEmailAndPassword(
          email: email, password: password)) as User;
      _userFromFirebaseUser(user);
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(
            builder: (context) => const MyHomePage(title: "Twitter")),
      );
    } on FirebaseAuthException catch (e) {
      if (e.code == 'wrong-password') {
        signin.showToast("The password provided is incorrect.", context); // <-- This does not work
      } else if (e.code == 'user-not-found') {
        signin.showToast("An account with that email does not exist.", context); // <-- This does not work
      }
    } catch (e) {
      signin.showToast("An unexpected error has occurred.", context); // <-- This does not work
    }
  }
}

This is the error that I am getting:

The method 'showToast' isn't defined for the type 'Signin'.
Try correcting the name to the name of an existing method, or defining a method named 'showToast'

CodePudding user response:

it may possible but you can easy different make it instead of your approach. set a static String message = "";

and..
on FirebaseAuthException catch (e) {
      if (e.code == 'wrong-password') {
        message = "The password provided is incorrect.";
      }

finally you can use it in Auth button..

showToast() {
    bool smallPhone = false;
    double width = MediaQuery.of(context).size.width;
    if (width <= 370) smallPhone = true;
    Widget toast = Container(
      padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(25.0),
        color: Colors.redAccent,
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          const SizedBox(
            width: 10.0,
          ),
          Text(
            AuthService.message, 
            style:
                TextStyle(fontSize: smallPhone ? 13 : 15, color: Colors.white),
          ),
        ],
      ),
    );

maybe it will help

CodePudding user response:

You can use callback but i don't think this is an elegant solution.

signInAction(
      String email, String password, {required void Function(String message) one rror}) async {
    try {
      User user = (await auth.signInWithEmailAndPassword(
          email: email, password: password)) as User;
      _userFromFirebaseUser(user);
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(
            builder: (context) => const MyHomePage(title: "Twitter")),
      );
    } on FirebaseAuthException catch (e) {
      if (e.code == 'wrong-password') {
        one rror("The password provided is incorrect.");
      } else if (e.code == 'user-not-found') {
        one rror("An account with that email does not exist.");
      }
    } catch (e) {
      one rror("An unexpected error has occurred."); 
    }
  }

and then you can call

authService.signInAction(email, password, 
   one rror:(message){
       showToast(message, context);
   }
)
  • Related