Flutter Provider showing data from wrong user

417 views Asked by At

In my application when I log in on 1 account (lets call him 'user1') and then logout of that user, then I log in on a second account ('user2'), my StreamProvider gets the correct UID from Firebase of the new user, but my StreamProviders below that use that 'uid' still show the data from the previous user.

This is an issue because in, for example, my StreamProvider<List> it gets the workouts from user1, and not from user2,... After HOT RESTARTING the app it will fix itself, but I need it to work without HOT Restarting

So I guess my question is, either, "what am I doing wrong?" or "how can I 'recreate' my StreamProviders (that use the UID) when the value of User/user.uid changes

Thanks in advance

This is the code in my main.dart, which contains all my Providers

void main() {
  runApp(MyApp());
}



class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.portraitUp,
      DeviceOrientation.portraitDown,
    ]);
    return MultiProvider(
      providers: [
        StreamProvider<User>(
          create: (_) => AuthService().user,
        ),
       
      ],
      child: Builder(
        builder: (BuildContext context) {
          final user = Provider.of<User>(context) ?? null;
         

          return MultiProvider(
            providers: [
              StreamProvider<List<Exercise>>(
                create: (_) => DatabaseService().exercises,
              ),
              StreamProvider<List<ExerciseCategory>>(
                create: (_) => DatabaseService().categories,
              ),
              StreamProvider<List<ExerciseEquipment>>(
                create: (_) => DatabaseService().equipment,
              ),
              StreamProvider<List<notification.Notification>>(
                create: (_) => DatabaseService().notifications,
              ),
              ChangeNotifierProvider<ExerciseFilter>(
                create: (_) => ExerciseFilter(),
              ),
              ChangeNotifierProvider<WorkoutChangeNotifier>(
                create: (_) => WorkoutChangeNotifier(),
              ),
              StreamProvider<List<UserExercise>>(
                create: (_) =>
                    DatabaseService(uid: user != null ? user.uid : '')
                        .userExercises,
              ),
              StreamProvider<List<WorkoutStreamProvider>>(
                create: (_) =>
                    DatabaseService(uid: user != null ? user.uid : '').workouts,
              ),
              StreamProvider<List<WorkoutHistory>>(
                create: (_) =>
                    DatabaseService(uid: user != null ? user.uid : '')
                        .workoutHistory,
              ),
              StreamProvider<UserSettings>(
                create: (_) =>
                    DatabaseService(uid: user != null ? user.uid : '').settings,
              ),
              StreamProvider<Nutrition>(
                create: (_) =>
                    DatabaseService(uid: user != null ? user.uid : '')
                        .nutrition,
              ),
            ],
            child: MaterialApp(
              theme: ThemeData(
                primarySwatch: Colors.grey,
                primaryTextTheme: TextTheme(
                  headline6: TextStyle(color: Colors.black, fontSize: 16.0),
                ),
                fontFamily: "Circular",
                backgroundColor: Colors.blueAccent,
              ),
              home: Wrapper(),
            ),
          );
        },
      ),
    );
  }
}

EDIT 1: get workouts code

List<WorkoutStreamProvider> _workoutStreamProviderListFromSnapshot(
    DocumentSnapshot snapshot,
  ) {
    //
    WorkoutExerciseSet _buildWorkoutExerciseSet(dynamic _set) {
      return WorkoutExerciseSet(
        reps: _set['reps'] ?? 0,
        weight: _set['weight'] ?? 0.0,
      );
    }

    List<WorkoutExerciseSet> _buildWorkoutExerciseSetList(dynamic sets) {
      List<WorkoutExerciseSet> setList = [];

      for (int i = 0; i < sets.length; i++) {
        setList.add(_buildWorkoutExerciseSet(sets[i]));
      }

      return setList;
    }

    WorkoutExercise _buildWorkoutExercise(dynamic exercise) {
      return WorkoutExercise(
        name: exercise['exerciseName'] ?? '',
        category: exercise['exerciseCategory'] ?? '',
        equipment: exercise['exerciseEquipment'] ?? '',
        restEnabled: exercise['restEnabled'] ?? true,
        restSeconds: exercise['restSeconds'] ?? 60,
        hasNotes: exercise['hasNotes'] ?? false,
        notes: exercise['notes'] ?? '',
        sets: _buildWorkoutExerciseSetList(exercise['sets']),
      );
    }

    List<WorkoutExercise> _buildWorkoutExerciseList(List<dynamic> exercises) {
      List<WorkoutExercise> workoutExerciseList = [];

      for (int i = 0; i < exercises.length; i++) {
        workoutExerciseList.add(
          _buildWorkoutExercise(exercises[i]),
        );
      }

      return workoutExerciseList;
    }

    WorkoutStreamProvider _buildWorkout(dynamic workout) {
      return WorkoutStreamProvider(
        id: workout['id'] ?? '',
        name: workout['workoutName'] ?? '',
        workoutNote: workout['workoutNote'] ?? '',
        exercises: _buildWorkoutExerciseList(workout['exercises']),
      );
    }

    List<WorkoutStreamProvider> workoutList = [];

    if (snapshot.exists && snapshot.data != null) {
      if (snapshot.data['workouts'] != null) {
        List<dynamic> workouts = snapshot.data['workouts'];

        for (int i = 0; i < workouts.length; i++) {
          workoutList.add(_buildWorkout(workouts[i]));
        }
      }
    }

    return workoutList;
  }

  Stream<List<WorkoutStreamProvider>> get workouts {
    print("GETTING WORKOUTS OF UID: " + uid);

    return userCollection
        .document(uid)
        .snapshots()
        .map(_workoutStreamProviderListFromSnapshot);
  }

UI

class WorkoutListWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final List<WorkoutStreamProvider> dbWorkouts =
        Provider.of<List<WorkoutStreamProvider>>(context) ?? [];

    final User user = Provider.of<User>(context) ?? null;

    final WorkoutChangeNotifier workout =
        Provider.of<WorkoutChangeNotifier>(context) ?? null;

    return ReorderableSliverList(
      delegate: ReorderableSliverChildListDelegate(
        [
          for (int i = 0; i < dbWorkouts.length; i++)
            Container(
              margin: EdgeInsets.all(16.0),
              child: InkWell(
                onTap: () {
                  workout.workoutStreamProviderToChangeNotifier(dbWorkouts[i]);
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (BuildContext context) => WorkoutViewPage(),
                    ),
                  );
                },
                child: Container(
                  padding: EdgeInsets.fromLTRB(8.0, 0.0, 8.0, 8.0),
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(6.0),
                    border: Border.all(
                      color: Colors.grey[400],
                      width: 1,
                    ),
                  ),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: <Widget>[
                          Container(
                            padding: EdgeInsets.only(left: 16.0),
                            child: Text(
                              dbWorkouts[i].name,
                              style: TextStyle(
                                fontSize: 16.0,
                                fontWeight: FontWeight.w500,
                              ),
                            ),
                          ),
                          Theme(
                            data: Theme.of(context).copyWith(
                              cardColor: Color.fromRGBO(35, 35, 35, 1),
                              dividerColor: Color.fromRGBO(70, 70, 70, 1),
                            ),
                            child: PopupMenuButton(
                              offset: Offset(0, 50),
                              shape: RoundedRectangleBorder(
                                borderRadius:
                                    BorderRadius.all(Radius.circular(8.0)),
                              ),
                              icon: Icon(
                                Icons.more_vert,
                              ),
                              onSelected: (selection) async {
                                if (selection == 'edit') {
                                  print('EDIT WORKOUT');
                                  workout.workoutStreamProviderToChangeNotifier(
                                      dbWorkouts[i]);

                                  Navigator.push(
                                    context,
                                    MaterialPageRoute(
                                      builder: (BuildContext context) =>
                                          WorkoutEditPage(),
                                    ),
                                  );
                                } else if (selection == 'duplicate') {
                                  print('DUPLICATE WORKOUT');

                                  dynamic result = await DatabaseService(
                                    uid: user != null ? user.uid : '',
                                  ).duplicateWorkout(dbWorkouts[i], dbWorkouts);

                                  if (result != null) {
                                    print("Workout Duplicated");
                                  }
                                } else if (selection == 'delete') {
                                  dynamic result = await DatabaseService(
                                    uid: user != null ? user.uid : '',
                                  ).removeWorkout(dbWorkouts[i], dbWorkouts);

                                  if (result != null) {
                                    print("Workout Deleted");
                                  }
                                }
                              },
                              itemBuilder: (BuildContext context) =>
                                  <PopupMenuItem>[
                                PopupMenuItem(
                                  height: 40.0,
                                  value: 'edit',
                                  child: Text(
                                    'Edit workout',
                                    style: TextStyle(
                                      color: Colors.white,
                                      fontSize: 17.0,
                                    ),
                                  ),
                                ),
                                PopupMenuItem(
                                  height: 40.0,
                                  value: 'duplicate',
                                  child: Text(
                                    'Duplicate workout',
                                    style: TextStyle(
                                      color: Colors.white,
                                      fontSize: 17.0,
                                    ),
                                  ),
                                ),
                                PopupMenuItem(
                                  height: 40.0,
                                  value: 'delete',
                                  child: Text(
                                    'Delete workout',
                                    style: TextStyle(
                                      color: Colors.white,
                                      fontSize: 17.0,
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ],
                      ),
                      for (int j = 0; j < dbWorkouts[i].exercises.length; j++)
                        Container(
                          padding: EdgeInsets.symmetric(
                              horizontal: 16.0, vertical: 2.0),
                          child: Text(dbWorkouts[i].exercises[j].equipment == ""
                              ? dbWorkouts[i]
                                      .exercises[j]
                                      .sets
                                      .length
                                      .toString() +
                                  ' x ' +
                                  dbWorkouts[i].exercises[j].name
                              : dbWorkouts[i]
                                      .exercises[j]
                                      .sets
                                      .length
                                      .toString() +
                                  ' x ' +
                                  dbWorkouts[i].exercises[j].name +
                                  " (" +
                                  dbWorkouts[i].exercises[j].equipment +
                                  ")"),
                        ),
                    ],
                  ),
                ),
              ),
            ),
        ],
      ),
      onReorder: (int oldIndex, int newIndex) {
        // Move Workout
        dynamic result = DatabaseService(
          uid: user != null ? user.uid : '',
        ).reorderWorkout(oldIndex, newIndex, dbWorkouts);
      },
    );
  }
}
1

There are 1 answers

1
Flame On BEST ANSWER

I managed to fix my issue by placing an if around my Multiprovider inside the builder, and either returning my SignIn() screen if user doesn't exist and otherwise I return my multiprovider, containing the providers, and the Wrapper()

This way I force my UI to rebuild on a change in my user provider and by forcing it to rebuild it has to recall my DatabaseService() functions with the new UID

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.portraitUp,
      DeviceOrientation.portraitDown,
    ]);
    return MultiProvider(
      providers: [
        StreamProvider<User>(
          create: (_) => AuthService().user,
        ),
      ],
      child: Builder(
        builder: (BuildContext context) {
          final user = Provider.of<User>(context) ?? null;

          return user == null
              ? MaterialApp(
                  theme: ThemeData(
                    primarySwatch: Colors.grey,
                    primaryTextTheme: TextTheme(
                      headline6: TextStyle(color: Colors.black, fontSize: 16.0),
                    ),
                    fontFamily: "Circular",
                    backgroundColor: Colors.blueAccent,
                  ),
                  home: SignIn(),
                )
              : MultiProvider(
                  providers: [
                    StreamProvider<List<Exercise>>(
                      create: (_) => DatabaseService().exercises,
                    ),
                    StreamProvider<List<ExerciseCategory>>(
                      create: (_) => DatabaseService().categories,
                    ),
                    StreamProvider<List<ExerciseEquipment>>(
                      create: (_) => DatabaseService().equipment,
                    ),
                    StreamProvider<List<notification.Notification>>(
                      create: (_) => DatabaseService().notifications,
                    ),
                    ChangeNotifierProvider<ExerciseFilter>(
                      create: (_) => ExerciseFilter(),
                    ),
                    ChangeNotifierProvider<WorkoutChangeNotifier>(
                      create: (_) => WorkoutChangeNotifier(),
                    ),
                    StreamProvider<List<UserExercise>>(
                      create: (_) =>
                          DatabaseService(uid: user != null ? user.uid : '')
                              .userExercises,
                    ),
                    StreamProvider<List<WorkoutStreamProvider>>(
                        create: (_) =>
                            DatabaseService(uid: user != null ? user.uid : '')
                                .workouts),
                    StreamProvider<List<WorkoutHistory>>(
                      create: (_) =>
                          DatabaseService(uid: user != null ? user.uid : '')
                              .workoutHistory,
                    ),
                    StreamProvider<UserSettings>(
                      create: (_) =>
                          DatabaseService(uid: user != null ? user.uid : '')
                              .settings,
                    ),
                    StreamProvider<Nutrition>(
                      create: (_) =>
                          DatabaseService(uid: user != null ? user.uid : '')
                              .nutrition,
                    ),
                  ],
                  child: MaterialApp(
                    theme: ThemeData(
                      primarySwatch: Colors.grey,
                      primaryTextTheme: TextTheme(
                        headline6:
                            TextStyle(color: Colors.black, fontSize: 16.0),
                      ),
                      fontFamily: "Circular",
                      backgroundColor: Colors.blueAccent,
                    ),
                    home: Wrapper(),
                  ),
                );
        },
      ),
    );
  }
}