0

I've searched everywhere and can't find a simple solution. I'm new to coding and new to Flutter/Dart.

I suspect this is a very basic problem. I need to pass a callback via an intermediary widget to the final widget.

Overview of the issue:

RootPage > TabNavigator > SearchPage > ProfilePage(with logout button on ProfilePage). Does not work.

In RootPage the offending code is:

  @override
  Widget build(BuildContext context) {
    switch (authStatus) {
      case AuthStatus.notDetermined:
        return _buildWaitingScreen();
      case AuthStatus.notSignedIn:
        return LoginPage(
          onSignedIn: _signedIn,
        );
      case AuthStatus.signedIn:
        return TabNavigation(
          ProfilePage(onSignedOut: _signedOut,)
        );
    }
    return null;
  }

RootPage > SearchPage (logout button on this SearchPage). Does work with this code:

@override
  Widget build(BuildContext context) {
    switch (authStatus) {
      case AuthStatus.notDetermined:
        return _buildWaitingScreen();
      case AuthStatus.notSignedIn:
        return LoginPage(
          onSignedIn: _signedIn,
        );
      case AuthStatus.signedIn:
        return SearchPage(
          onSignedOut: _signedOut,
        );
    }
    return null;
  }

Code snippet:

class ProfilePage extends StatelessWidget {
  ProfilePage({this.onSignedOut});
  final VoidCallback onSignedOut;

 @override
    Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: new Text('Manage Profile'),
            actions: <Widget> [
              new FlatButton(
                child: new Text('Logout', style: new TextStyle(fontSize: 17.0, color: Colors.white)),
                onPressed: () => _signOut(context)
.....
....


class _RootPageState extends State<RootPage> {
  AuthStatus authStatus = AuthStatus.notDetermined;

@override
  Widget build(BuildContext context) {
    switch (authStatus) {
      case AuthStatus.notDetermined:
        return _buildWaitingScreen();
      case AuthStatus.notSignedIn:
        return LoginPage(
          onSignedIn: _signedIn,
        );
      case AuthStatus.signedIn:
        return TabNavigation(
          ProfilePage(onSignedOut: _signedOut), 
        );
    }
    return null;
  }

Homepage of my app is RootPage, which manages the user's login status. Once logged in, the RootPage returns TabNavigation, which is a utility that manages the bottomNavigationbar, and returns SearchPage by default (i.e. setState returns currentPage = SearchPage).

I now wish to have the logout button on ProfilePage.

I don't know how to get the onPressed callback function to pass it's output back to RootPage.

Difficult to explain without pasting in the full code, but I hope you get the concept.

2
  • Are you getting any error in the console? Commented Aug 23, 2018 at 4:44
  • No, no errors in the console Commented Aug 23, 2018 at 8:02

2 Answers 2

2

You can use an InheritedWidget at root level i.e. at _RootPageState class. Now you can pass any information(data) down at any point in hierarchy. In your case passed onPressed will get use at ProfilePage.

class LogoutAction extends InheritedWidget {
  const LogoutAction({
    Key key,
    @required this.logoutButtonClick,
    @required Widget child,
  }) : assert(logoutButtonClick != null),
       assert(child != null),
       super(key: key, child: child);

  final VoidCallback logoutButtonClick;

  static LogoutAction of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(LogoutAction);
  }

  @override
  bool updateShouldNotify(LogoutAction old) => logoutButtonClick != old.logoutButtonClick;
}

now this LogoutAction widget can be used at

class _RootPageState extends State<RootPage> {
  AuthStatus authStatus = AuthStatus.notDetermined;

  _logoutClick() {
    //your code
  }

  @override
  Widget build(BuildContext context) {
    return LogoutAction(
      logoutButtonClick: _logoutClick,
      child: //todo: child widget that will use ProfilePage
    );
  }
}

and your logout button will look like:

FlatButton(
  onPressed: LogoutAction.of(context).logoutButtonClick
)
Sign up to request clarification or add additional context in comments.

Comments

0

As it is working in SearchPage, then it should be straightforward. Refer the below code,

class SearchPage extends StatefulWidget {
  final VoidCallback onSignedOut;

  SearchPage(this.onSignedOut); //getting from RootPage (might be via TabNavigator)

  @override
  State<StatefulWidget> createState() {
    return new _SearchPage();
  }

}

class _SearchPage extends State<SearchPage> {
  @override
  Widget build(BuildContext context) {
    var route = MaterialPageRoute(
        builder: (context) => ProfilePage(this.widget.onSignedOut)); // sending the callback to ProfilePage
    Navigator.push(context, route);
  }
}

class ProfilePage extends StatelessWidget {
  ProfilePage(this.onSignedOut);
  final VoidCallback onSignedOut;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
        title: new Text('Manage Profile'),
    actions: <Widget> [
    new FlatButton(
    child: new Text('Logout', style: new TextStyle(fontSize: 17.0, color: Colors.white)),
    onPressed: () => onSignedOut() //invoking the callback which will execute in RootPage
    //....
  }
}

Note: In your ProfilePage, onPressed method name looks wrong _signOut(context). If you are using some private method which calls onSignedOut that is fine. If not, you have to use onSignedOut()

1 Comment

Thanks for the response. This doesn't solve my problem. I've rewritten the question with additional detail and code snippets.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.