Zero Live
Zero Live

Reputation: 1843

Dynamic variable in flutter. Any better way to do this?

[Edited] I have this application with multilevel user application where I have functions based on roles. Currently, I am saving user response in shared preferences and fetching it by getting it's instance whenever I need it. And also, I am using different screens and different widgets for each role. But there has to be a better way to do it. I am so confused with singleton pattern and making global variables in dart.

Here's my code:

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SharedPreferences.getInstance().then((prefs) {
    var user=prefs.getString("role");
    runApp(MultiProvider(
      providers: [
        ChangeNotifierProvider<RoleNotifier>(
          create: (_) => RoleNotifier(user),
        ),
      ],
      child: MyApp(),
    ));
  });
}

void setRole(String role) async {
    Provider.of<RoleNotifier>(context, listen:false).setUser(role);
    await SharedPreferences.getInstance().then((prefs){
      prefs.setString("role", role);
   });
  }
_login() async {
    try {
      setState(() {
        _isbusy = true;
      });
      var data = {"username": _emailc.text, "password": _pass.text};
      var response = await CallApi().postData(data, 'login');
      SharedPreferences local = await SharedPreferences.getInstance();
      var res = response.data;
      print(res);
      if (res['success']) {
        local.setString('token', res['data']['token']);
        if (res['data']['role'] == 'admin') {
              setRole(res['data']['role']);
              local.setString('info', json.encode(res['data']));
              Navigator.pushReplacement(context,
                  MaterialPageRoute(builder: (context) => AdminDashBoard()));
        } else if (res['data']['role'] == 'dev') {

               setRole(res['data']['role']);
              local.setString('post', res['data']['role']);
              local.setString('info', json.encode(res['data']));
              Navigator.pushReplacement(context,
                  MaterialPageRoute(builder: (context) => DevDashBoard()));
        } else if (res['data']['role'] == 'user') {
              setRole(res['data']['role']);
              local.setString('post', res['data']['role']);
              local.setString('info', json.encode(res['data']));
              Navigator.pushReplacement(context,
                  MaterialPageRoute(builder: (context) => UserDashBoard()));
        } 
      } else {
        print('error');
        setState(() {
          _isbusy = false;
        });
        showSimpleFlushbar(context, "An Error Occurred!");
      }
    } on DioError catch (e) {
      print(e);
      setState(() {
        _isbusy = false;
      });
      print(e.response.data);
      print(e.response.headers);
      print(e.response.request);
      showSimpleFlushbar(context,
          "Login Failed! Please Check your credentials and try again.");
    }
  }

And to access the variables:

SharedPreferences.getInstance().then((prefs) {
      var data = jsonDecode(prefs.getString("info"));
      setState(() {
        email = data['email'];
        post = data['role'];
      });
    });

The problem is, I have to run this on initState in every screen and there is a delay in fetching data which throws an exception for small time. I just figured out this is working.

(Provider.of<RoleNotifier>(context).getUser()=="admin")?AdminWidget():SizedBox(),

Now I can access the data from anywhere using provider. But is there any better way to do this? I've heard a lot about singleton pattern and in my case even though it works, it seems like I am doing something wrong. Like I am listening to the value that is static immediately after login is completed.

Upvotes: 1

Views: 2048

Answers (2)

Doc
Doc

Reputation: 11651

SharedPreferences prefs;// file level global variable

main(){
    SharedPreferences.getInstance().then((p)=>prefs = p);
    // do whatever
    runApp(MyApp());
}

Now, don't use SharedPreferences.getInstance() when needed but use the global variable created.

Like

prefs.getString('name');

or

prefs.setString('foo','bar');

For example

class Foo extends StatelessWidget{
    Widget build(context){
        var name = prefs.getString('name');// don't use var prefs = await SharedPreferences.getInstance();
        return Text("name is $name");
    }
}

Upvotes: 3

Bret Hagen
Bret Hagen

Reputation: 123

Why not create a User class and extend it with Provider?

Then based on the Consumers to build dynamic widgets you can pump out what ever you want based on the User.role for the selected user.

In your Singleton you can add a Singleton().selectedUser var and once a user logs in or what ever process they follow you can assign it to that. Use this selectedUser var for your Provider.value.

If you need example code let me know.

Upvotes: 0

Related Questions