Search code examples
flutterdartrefactoringnavigation-drawer

Refactoring Dart Code into a separate file


I have this code where I have the sidebar (drawer) in my app. I have created a separate file drawer.dart which looks somewhat like this :

import 'package:flutter/material.dart';

class DrawerClass extends StatefulWidget {
  @override
  _DrawerClassState createState() => _DrawerClassState();
}

class _DrawerClassState extends State<DrawerClass> {
  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: ListView(
        padding: EdgeInsets.zero,
        children: [
          DrawerHeader(
            child: CircleAvatar(
              backgroundColor: Theme.of(context).primaryColor,
              radius: 30,
              child: Icon(
                Icons.pets,
                size: 60,
                color: Colors.white,
              ),
            ),
          ),
          ListTile(
            leading: Icon(Icons.home),
            title: Text("Home"),
            onTap: () {
              Navigator.pushReplacementNamed(context, "/home");
            },
          ),
          ListTile(
            leading: Icon(
              Icons.report,
            ),
            title: Text("Report"),
            onTap: () {
              Navigator.pushReplacementNamed(context, "/report");
            },
          ),
          ListTile(
            leading: Icon(
              Icons.settings,
            ),
            title: Text("Settings"),
            onTap: () {
              Navigator.pop(context);
            },
          ),
        ],
      ),
    );
  }
}

Now I have three different files: home.dart , report.dart, settings.dart. This refactored code will work perfectly when used in settings.dart but not in other two files. Example, if I use this in report.dart I'll have to change it's onTap status to Navigator.pop. I need to use drawer.dart in all the other 3 files changing only the onTap status in every file.

Any help will be appreciated:)


Solution

  • One way to do this is like so.

    enum ScreenName {
      Home,
      Report,
      Settings,
    }
    

    Use this enum as a property (parentScreen) of DrawerClass so it knows which screen it is in.

    class DrawerClass extends StatefulWidget {
      final ScreenName parentScreen;
    
      const DrawerClass({@required this.parentScreen});
    
      @override
      _DrawerClassState createState() => _DrawerClassState();
    }
    
    class _DrawerClassState extends State<DrawerClass> {
      @override
      Widget build(BuildContext context) {
        return Drawer(
          child: ListView(
            padding: EdgeInsets.zero,
            children: [
              // other children,
              ListTile(
                leading: Icon(Icons.home),
                title: Text("Home"),
                onTap: () {
                  if (widget.parentScreen == ScreenName.Home)
                    Navigator.pop(context);
                  else
                    Navigator.pushReplacementNamed(context, "/home");
                },
              ),
              ListTile(
                leading: Icon(Icons.report),
                title: Text("Report"),
                onTap: () {
                  if (widget.parentScreen == ScreenName.Report)
                    Navigator.pop(context);
                  else
                    Navigator.pushReplacementNamed(context, "/report");
                },
              ),
              ListTile(
                leading: Icon(Icons.settings),
                title: Text("Settings"),
                onTap: () {
                  if (widget.parentScreen == ScreenName.Settings)
                    Navigator.pop(context);
                  else
                    Navigator.pushReplacementNamed(context, "/settings");
                },
              ),
            ],
          ),
        );
      }
    }
    

    Then use DrawerClass like so. For example, for setting screen -

    DrawerClass(parentScreen: ScreenName.Settings)