LostTexan
LostTexan

Reputation: 891

converting global variables to riverpod providers in flutter app

I am having a hard time using Riverpod providers in my flutter app. I have previously used global variables but I want to convert them to a provider class.

I removed the original code because of character limits.

Can you please help me with this? Thank you

UPDATE This is what I have done so far. Am I correct in what I have changed? Here is the provider class:

class GlobalsProvider extends ChangeNotifier {
  GlobalsProvider._();

  // This is assigned in the Login screen
  static final currentUid = StateProvider<String?>((ref) => null);
  static final currentUEmail = StateProvider<String?>((ref) => null);

  // This is assigned in  agent_profile screen
  //String agentDocumentId;
  // ======  populated in login_screen.dart  =======
  String? companyId;
  String? mlsId;
  String? currentTrxnId;
  String? currentCompanyName;
  String? currentCompanyState;
  String? currentUserId;
  String? currentUserState;
  String? currentUserName;
  // ===============================================
  String? selectedState;
  String? selectedUserState;
  String? selectedTrxnState;
  String? selectedCompany;
  String? selectedUser;
  int? targetScreen;
  bool? newEvent;

  bool? newTrxn;
  bool? newUser;
  bool? newCompany;

  // changeCurrentUId(String value) {
  //   companyId = value;
  //   notifyListeners();
  // }

  void changeCurrentUId(WidgetRef ref, String newUID){
    ref.read(GlobalsProvider.currentUid.notifier).state = newUID;
    // or if you need previous state use update method
    //ref.read(MyGlobalProvider.currentUid.notifier).update((previousUID)=> newUID);
  }

  // changecurrentUEmail(String value) {
  //   currentUEmail = value;
  //   notifyListeners();
  // }  

  void changecurrentUEmail(WidgetRef ref, String newUEmail){
    ref.read(GlobalsProvider.currentUEmail.notifier).state = newUEmail;
    // or if you need previous state use update method
    //ref.read(MyGlobalProvider.currentUid.notifier).update((previousUID)=> newUID);
  }
  
  changeCompanyId(String value) {
    companyId = value;
    notifyListeners();
  }

  changeMlsId(String value) {
    mlsId = value;
    notifyListeners();
  }

  changeCurrentTrxnId(String value) {
    currentTrxnId = value;
    notifyListeners();
  }

  changeCurrentCompanyName(String value) {
    currentCompanyName = value;
    notifyListeners();
  }

  changeCurrentCompanyState(String value) {
    currentCompanyState = value;
    notifyListeners();
  }

  changeCurrentUserId(String value) {
    currentUserId = value;
    notifyListeners();
  }

  changeCurrentUserState(String value) {
    currentUserState = value;
    notifyListeners();
  }

  changeCurrentUserName(String value) {
    currentUserName = value;
    notifyListeners();
  }

  changeSelectedState(String value) {
    selectedState = value;
    notifyListeners();
  }

  changeSelectedUserState(String value) {
    selectedUserState = value;
    notifyListeners();
  }

  changeSelectedTrxnState(String value) {
    selectedTrxnState = value;
    notifyListeners();
  }

  changeSelecteCompany(String value) {
    selectedCompany = value;
    notifyListeners();
  }

  changeSelectedUser(String value) {
    selectedUser = value;
    notifyListeners();
  }

  changeTargetScreen(int value) {
    targetScreen = value;
    notifyListeners();
  }

  changeNewEvent(bool value) {
    newEvent = value;
    notifyListeners();
  }

  changeNewTrxn(bool value) {
    newTrxn = value;
    notifyListeners();
  }

  changeNewUser(bool value) {
    newUser = value;
    notifyListeners();
  }

  changeNewCompany(bool value) {
    newCompany = value;
    notifyListeners();
  }
}

Now, how and where do I implement the ref.read and the watch?

Here is the UserProfileScreen class:

class UserProfileScreen extends ConsumerStatefulWidget {
  static const String id = 'user_profile_screen';
  final Users? users;

  UserProfileScreen([this.users]);

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

class _UserProfileScreenState extends ConsumerState<UserProfileScreen> {
  final globalProvider =
            Provider.of<GlobalsProvider>(context, listen: false);
  final _db = FirebaseFirestore.instance;

  final emailController = TextEditingController();
  final passwordController = TextEditingController();
  final fNameController = TextEditingController();
  final lNameController = TextEditingController();
  final address1Controller = TextEditingController();
  final address2Controller = TextEditingController();
  final cityController = TextEditingController();
  final stateController = TextEditingController();
  final zipController = TextEditingController();
  final cellPhoneController = TextEditingController();
  final officePhoneController = TextEditingController();
  final companyController = TextEditingController();
  final mlsController = TextEditingController();

  @override
  
  // Dispose of all the TextControllers when done using them so they don't consume memory
  @override
  void dispose() {
  }

  String? _currentUserState = globals.currentAgentState; <<< How would I set this variable using the provider?
  String? _currentCompanyState;
  String? _currentCompany;
  String? _currentMls;

  getCurrentAgentProfile() async {

    if (globals.newUser == true) { <<<  How to replace global with provider?
      final DocumentSnapshot currentAgencyProfile =
          await companyRef.doc(globals.agencyId).get();<<<  How to replace global with provider?

      emailController.text = "";
      fNameController.text = "";
      lNameController.text = "";
      address1Controller.text = currentAgencyProfile['address1'];
      address2Controller.text = currentAgencyProfile['address2'];
      cityController.text = currentAgencyProfile['city'];
      zipController.text = currentAgencyProfile['zipCode'].toString();
      cellPhoneController.text = currentAgencyProfile['cellPhone'];
      officePhoneController.text = currentAgencyProfile['officePhone'];
      companyController.text = currentAgencyProfile['name'];
      // Updates State
      Future.delayed(Duration.zero, () {
        final agentProvider =
            Provider.of<AgentProvider>(context, listen: false);
        agentProvider.loadValues(Users());
      });
    } else {
      final DocumentSnapshot currentAgentProfile =
          await usersRef.doc(globals.currentAgentId).get();

      // existing record
      // Updates Controllers
      emailController.text = currentAgentProfile["email"] ?? "";
      fNameController.text = currentAgentProfile['fName'] ?? "";
      lNameController.text = currentAgentProfile['lName'] ?? "";
      address1Controller.text = currentAgentProfile['address1'] ?? "";
      address2Controller.text = currentAgentProfile['address2'] ?? "";
      cityController.text = currentAgentProfile['city'] ?? "";
      //stateController.text = currentAgentProfile.data()['state'];
      _currentUserState = currentAgentProfile['state'] ?? "";
      if (currentAgentProfile.get('state') == "" ||
          currentAgentProfile.get('state') == null) {
        _currentCompanyState = globals.currentAgentState;
      } else {
        _currentCompanyState = currentAgentProfile['state'] ?? "";
      }
      ;
      zipController.text = currentAgentProfile['zipCode'].toString() ?? "";
      cellPhoneController.text = currentAgentProfile['cellPhone'] ?? "";
      officePhoneController.text = currentAgentProfile['officePhone'] ?? "";
      companyController.text = currentAgentProfile['agency'] ?? "";
      mlsController.text = currentAgentProfile['mls'] ?? "";
      // Updates State
      Future.delayed(Duration.zero, () {
        final userProvider =
            Provider.of<UserProvider>(context, listen: false);
        userProvider.loadValues(widget.users!);
      });
    }
  }

  List<DropdownMenuItem<String>>? _dropDownState;

  List<DropdownMenuItem<String>> getDropDownState() {
    List<DropdownMenuItem<String>> items = [];
    for (String state in globals.states/* as Iterable<String>*/) {
      items.add(DropdownMenuItem(
          value: state,
          child: Text(
            state,
          )));
    }
    return items;
  }

  void changedDropDownState(String? selectedState) {
    setState(() {
      _currentUserState = selectedState;
      globals.selectedAgentState = selectedState;
      globals.currentAgentState = selectedState;
    });
  }

  void changedDropDownAgency(String? selectedAgency) {
    setState(() {
      _currentCompany = selectedAgency;
      globals.selectedAgency = selectedAgency;
      globals.currentAgencyName = selectedAgency;
    });
  }

  void changedDropDownMls(String? selectedMls) {
    setState(() {
      _currentMls = selectedMls;
      globals.mlsId = selectedMls;
    });
  }

  @override
  void initState() {
    getCurrentAgentProfile();
    if (globals.currentAgentState == "" || globals.currentAgentState == null) {
      _currentUserState = globals.currentAgencyState;
    } else {
      _currentUserState = globals.currentAgentState;
    }
    ;
    _currentCompany = globals.agencyId;
    _currentCompanyState = globals.currentAgencyState;
    super.initState();

    _dropDownState = getDropDownState();
  }

  @override
  Widget build(BuildContext context) {
    // Get the stream of agents created in main.dart
    final agentProvider = Provider.of<AgentProvider>(context);
    final _firestoreService = FirestoreService();

    return Scaffold(
      appBar: AppBar(
        title: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Image.asset('assets/images/Appbar_logo.png',
                fit: BoxFit.cover, height: 56),
          ],
        ),
      ),
      backgroundColor: Colors.white,
      body: SafeArea(
        child: SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.all(20.0),
            child: Column(
              children: <Widget>[
                const Text(
                  'Agent Profile',
                  style: TextStyle(
                    fontSize: 30,
                  ),
                ),
                const SizedBox(
                  height: 8.0,
                ),
                // Email entry text field
                TextField(
                  controller: fNameController,
                  keyboardType: TextInputType.text,
                  textAlign: TextAlign.center,
                  onChanged: (value) {
                    agentProvider.changefName(value);
                    if (globals.currentAgentState == "" ||
                        globals.currentAgentState == null) {
                      _currentUserState = globals.currentAgencyState;
                    } else {
                      _currentUserState = globals.currentAgentState;
                    }
                    ;
                  },
                  decoration: const InputDecoration(
                      hintText: 'First Name', labelText: 'First Name'),
                ),
                const SizedBox(
                  height: 8.0,
                ),
                TextField(
                  controller: lNameController,
                  keyboardType: TextInputType.text,
                  textAlign: TextAlign.center,
                  onChanged: (value) {
                    agentProvider.changelName(value);
                    if (globals.currentAgentState == "" ||
                        globals.currentAgentState == null) {
                      _currentUserState = globals.currentAgencyState;
                    } else {
                      _currentUserState = globals.currentAgentState;
                    }
                    ;
                  },
                  decoration: const InputDecoration(
                      hintText: 'Last Name', labelText: 'Last Name'),
                ),
                const SizedBox(
                  height: 8.0,
                ),
                Container(
                  child: StreamBuilder(
                      stream: _db.collection('agency').snapshots(),
                      builder: (BuildContext context, AsyncSnapshot snapshot) {
                        if (snapshot.data == null) {
                          return const Center(
                            child: CircularProgressIndicator(),
                          );
                        } else {
                          return DropdownButton<String>(
                            hint: const Text("Select Agency"),
                            value: _currentCompany,
                            onChanged: changedDropDownAgency,
                            items: snapshot.data.docs
                                .map<DropdownMenuItem<String>>((document) {
                              return DropdownMenuItem<String>(
                                value: document.id,
                                child: Text(document.data()['name']),
                              );
                            }).toList(),
                          );
                        }
                      }),
                ),
                const SizedBox(
                  height: 8.0,
                ),
                TextField(
                  controller: address1Controller,
                  keyboardType: TextInputType.text,
                  textAlign: TextAlign.center,
                  onChanged: (value) {
                    agentProvider.changeaddress1(value);
                    if (globals.currentAgentState == "" ||
                        globals.currentAgentState == null) {
                      _currentUserState = globals.currentAgencyState;
                    } else {
                      _currentUserState = globals.currentAgentState;
                    }
                    ;
                  },
                  decoration: const InputDecoration(
                      hintText: 'Address 1', labelText: 'Address 1'),
                ),
                const SizedBox(
                  height: 8.0,
                ),
                TextField(
                  controller: address2Controller,
                  textAlign: TextAlign.center,
                  onChanged: (value) {
                    agentProvider.changeaddress2(value);
                    if (globals.currentAgentState == "" ||
                        globals.currentAgentState == null) {
                      _currentUserState = globals.currentAgencyState;
                    } else {
                      _currentUserState = globals.currentAgentState;
                    }
                    ;
                  },
                  decoration: const InputDecoration(
                      hintText: 'Address 2', labelText: 'Address 2'),
                ),
                const SizedBox(
                  height: 8.0,
                ),
                TextField(
                  controller: cityController,
                  keyboardType: TextInputType.emailAddress,
                  textAlign: TextAlign.center,
                  onChanged: (value) {
                    agentProvider.changecity(value);
                    if (globals.currentAgentState == "" ||
                        globals.currentAgentState == null) {
                      _currentUserState = globals.currentAgencyState;
                    } else {
                      _currentUserState = globals.currentAgentState;
                    }
                    ;
                  },
                  decoration: const InputDecoration(
                      hintText: 'City', labelText: 'City'),
                ),
                const SizedBox(
                  height: 8.0,
                ),
                DropdownButton(
                  value: _currentUserState,
                  items: _dropDownState,
                  hint: const Text('Choose State'),
                  onChanged: changedDropDownState,
                ),
                const SizedBox(
                  height: 8.0,
                ),
                TextField(
                  controller: zipController,
                  keyboardType: TextInputType.number,
                  textAlign: TextAlign.center,
                  onChanged: (value) {
                    agentProvider.changezipCode(value);
                    if (globals.currentAgentState == "" ||
                        globals.currentAgentState == null) {
                      _currentUserState = globals.currentAgencyState;
                    } else {
                      _currentUserState = globals.currentAgentState;
                    }
                    ;
                  },
                  decoration: const InputDecoration(
                      hintText: 'Zip Code', labelText: 'Zip Code'),
                ),
                const SizedBox(
                  height: 8.0,
                ),
                TextField(
                  inputFormatters: [maskFormatter],
                  controller: cellPhoneController,
                  keyboardType: TextInputType.phone,
                  textAlign: TextAlign.center,
                  onChanged: (value) {
                    agentProvider.changecellPhone(value);
                    if (globals.currentAgentState == "" ||
                        globals.currentAgentState == null) {
                      _currentUserState = globals.currentAgencyState;
                    } else {
                      _currentUserState = globals.currentAgentState;
                    }
                    ;
                  },
                  decoration: const InputDecoration(
                      hintText: 'Cell Phone', labelText: 'Cell Phone'),
                ),
                const SizedBox(
                  height: 8.0,
                ),
                TextField(
                  inputFormatters: [maskFormatter],
                  controller: officePhoneController,
                  keyboardType: TextInputType.phone,
                  textAlign: TextAlign.center,
                  onChanged: (value) {
                    agentProvider.changeofficePhone(value);
                    if (globals.currentAgentState == "" ||
                        globals.currentAgentState == null) {
                      _currentUserState = globals.currentAgencyState;
                    } else {
                      _currentUserState = globals.currentAgentState;
                    }
                    ;
                  },
                  decoration: const InputDecoration(
                      hintText: 'Office Phone', labelText: 'Office Phone'),
                ),
                const SizedBox(
                  height: 8.0,
                ),
                Container(
                  child: StreamBuilder(
                      stream: _db.collection('mls')
                          .where('mlsState', isEqualTo: globals.currentAgentState).snapshots(),
                      builder: (BuildContext context, AsyncSnapshot mlsSnapshot) {
                        if (mlsSnapshot.data == null) {
                          return const Center(
                            child: CircularProgressIndicator(),
                          );
                        } else {
                          return DropdownButton<String>(
                            hint: const Text("Select MLS"),
                            value: _currentMls,
                            onChanged: changedDropDownMls,
                            items: mlsSnapshot.data.docs
                                .map<DropdownMenuItem<String>>((document) {
                              return DropdownMenuItem<String>(
                                value: document.id,
                                child: Text(document.data()['mlsName']),
                              );
                            }).toList(),
                          );
                        }
                      }),
                ),
                const SizedBox(
                  height: 8.0,
                ),
                RoundedButton(
                  title: 'Save',
                  colour: Colors.blueAccent,
                  onPressed: () async {
                    setState(() {
                      showSpinner = true;
                    });
                    try {
                      agentProvider.saveAgent();
                      globals.currentAgentName = fNameController.value.text +
                          ' ' +
                          lNameController.value.text;
                      globals.currentAgentState = _currentUserState;
                      await _firestoreService.saveDeviceToken();
                      globals.targetScreen = 0;
                      Navigator.of(context).pushReplacement(MaterialPageRoute(
                          builder: (context) => MainScreen()));

                      setState(() {
                        showSpinner = false;
                      });
                    } catch (e) {
                      // todo: add better error handling
                      print(e);
                    }
                  },
                ),
                const SizedBox(
                  height: 8.0,
                ),

                (widget != null)
                    ? RoundedButton(
                        title: 'Delete',
                        colour: Colors.red,
                        onPressed: () async {
                          setState(() {
                            showSpinner = true;
                          });
                          try {
                            agentProvider.deleteAgent(globals.currentUid);
                            globals.targetScreen = 2;
                            Navigator.push(
                                context,
                                MaterialPageRoute(
                                    builder: (context) => MainScreen()));
                            //Navigator.pushNamed(
                            //    context, AgentDashboardScreen.id);

                            setState(() {
                              showSpinner = false;
                            });
                          } catch (e) {
                            // todo: add better error handling
                            print(e);
                          }
                        },
                      )
                    : Container()
              ],
            ),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          setState(() {
            showSpinner = true;
          });
          try {
            agentProvider.saveAgent();
            globals.targetScreen = 0;
            await _firestoreService.saveDeviceToken();
            Navigator.push(
              context,
              new MaterialPageRoute(
                builder: (context) => MainScreen(),
              ),
            );
            setState(() {
              showSpinner = false;
            });
          } catch (e) {
            // todo: add better error handling
            print(e);
          }
        },
        backgroundColor: kPrimaryColor,
        child: const Icon(
          Icons.assignment_turned_in_outlined,
          color: Colors.blueAccent,
        ),
      ),
    );
  }
}

I'm sorry I am so stupid here but here are some questions I still have:

  1. How do I add the provider to the UserProfileScreen class?
  2. How do I use the provider to get the value from the provider and replace the global variable?
  3. How and where do I put the ref.read methods?

I really appreciate your answer and help but I still don't understand.

Upvotes: 3

Views: 777

Answers (1)

Sayyid J
Sayyid J

Reputation: 1573

you need to separate this variable into several class or providers as much as possible, when you call notifylisteners() or you watch and change it, it will rebuild all the listener even if they don't need to be rebuilt..

my sugesstion is :

class MyGlobalProvider {
  //this is just helper class, private its constructor
  MyGlobalProvider._();
  
  static final currentUid = StateProvider<String?>((ref) => null);
  static final currentUEmail = StateProvider<String?>((ref) => null);

  static final companyID = StateProvider<String?>((ref) => null);

  static final targetScreen = StateProvider<String?>((ref) => null);

  static final isNewUser = StateProvider<bool?>((ref) => null);
  static final isNewCompany = StateProvider<bool>((ref) => false);
}

one time read for update :

void updateUID(WidgetRef ref,String newUID){
    ref.read(MyGlobalProvider.currentUid.notifier).state = newUID;
    // or if you need previous state use update method
    ref.read(MyGlobalProvider.currentUid.notifier).update((previousUID)=> newUID);
  }

watch:

Consumer(
  builder: (context, ref, child){
    final uid = ref.watch(MyGlobalProvider.currentUid);
    return Text(uid ?? '');
  },);

Upvotes: 1

Related Questions