Home > Mobile >  Navigator with bloc listener
Navigator with bloc listener

Time:08-10

Suppose I have Form in screen A with save button that run post action in cubit:

Future<void> postAssignment(List<Assigment?> assignments) async {
    emit(state.copyWith(status: AssignmentStatus.posting));

    try {
      await _warehouseRepository.postAssignments(
          assignments.map((a) => AssigmentApi.Assigment.toApi(a!)).toList());

      emit(state.copyWith(status: AssignmentStatus.success));
    } on Exception catch (e) {
      print("Error message: ${e.toString()}");
      emit(state.copyWith(status: AssignmentStatus.failure));
    }
  }

After this I want to stay in screen A with reseting state and I want to show snackBar that item is posted. So I have BlocListener for it:

BlocListener<AssignmentCubit, AssignmentState>(
                listener: (context, state) async {
                  print('AssignmentCubit-------------->: $state');
                  if (state.status.isPosting) {
                    AppKeys.NAVIGATOR_KEY.currentState?.pushNamed(
                      SplashPage.routeName,
                    );
                  }
                  if (state.status.isSuccess) {
                    await context.read<ViewItemCubit>().fetchViewItems(
                          int.parse(
                            context.read<ItemBarcodeCubit>().state,
                          ),
                        );
                    final snackBar = SnackBar(
                      duration: Duration(seconds: 2),
                      content: Text('added'),
                      backgroundColor: Colors.green,
                    );
                    ScaffoldMessenger.of(context).showSnackBar(snackBar);
                  } else {
                    AppKeys.NAVIGATOR_KEY.currentState?.popUntil(
                      (route) =>
                          route.settings.name == ItemLocatePage.routeName,
                    );
                  }
                },
              ),

but I think the state isn't reset and it's stacking, this is the result if I post first item:

I/flutter (30679): AssignmentCubit-------------->: AssignmentState(AssignmentStatus.posting, [])
I/flutter (30679): AssignmentCubit-------------->: AssignmentState(AssignmentStatus.success, [])

second item:

I/flutter (30679): AssignmentCubit-------------->: AssignmentState(AssignmentStatus.posting, [])
I/flutter (30679): AssignmentCubit-------------->: AssignmentState(AssignmentStatus.posting, [])
I/flutter (30679): AssignmentCubit-------------->: AssignmentState(AssignmentStatus.success, [])
I/flutter (30679): AssignmentCubit-------------->: AssignmentState(AssignmentStatus.success, [])

and so on:

I/flutter (30679): AssignmentCubit-------------->: AssignmentState(AssignmentStatus.posting, [])
I/flutter (30679): AssignmentCubit-------------->: AssignmentState(AssignmentStatus.posting, [])
I/flutter (30679): AssignmentCubit-------------->: AssignmentState(AssignmentStatus.posting, [])
I/flutter (30679): AssignmentCubit-------------->: AssignmentState(AssignmentStatus.success, [])
I/flutter (30679): AssignmentCubit-------------->: AssignmentState(AssignmentStatus.success, [])
I/flutter (30679): AssignmentCubit-------------->: AssignmentState(AssignmentStatus.success, [])

thanks to this the snackBar appears 3 times. Generally, I think the problem is in Navigator, because If I posted item the state isn't reset (maybe screen isn't dispose?). What is wrong?

Edit: build method:

@override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () {
        AppKeys.NAVIGATOR_KEY.currentState?.pushNamedAndRemoveUntil(
          HomePage.routeName,
          (route) => false,
        );
        return Future.value(true);
      },
      child: BlocBuilder<ViewItemFormCubit, ViewItem?>(
        builder: (context, state) {
          final dropdownValue =
              context.read<ViewItemFormCubit>().state == ViewItem.empty()
                  ? null
                  : context.read<ViewItemFormCubit>().state;
          return MultiBlocListener(
            listeners: [
              BlocListener<ViewItemCubit, ViewItemState>(
                listener: (context, state) {
                  if (state.status.isLoading) {
                    AppKeys.NAVIGATOR_KEY.currentState?.pushNamed(
                      SplashPage.routeName,
                    );
                  } else {
                    AppKeys.NAVIGATOR_KEY.currentState?.popUntil(
                      (route) =>
                          route.settings.name == ItemLocatePage.routeName,
                    );
                  }
                },
              ),
              BlocListener<AssignmentCubit, AssignmentState>(
                listener: (context, state) async {
                  print('AssignmentCubit-------------->: $state');
                  if (state.status.isPosting) {
                    AppKeys.NAVIGATOR_KEY.currentState?.pushNamed(
                      SplashPage.routeName,
                    );
                  }
                  if (state.status.isSuccess) {
                    await context.read<ViewItemCubit>().fetchViewItems(
                          int.parse(
                            context.read<ItemBarcodeCubit>().state,
                          ),
                        );
                    final snackBar = SnackBar(
                      duration: Duration(seconds: 2),
                      content: Text('added'),
                      backgroundColor: Colors.green,
                    );
                    ScaffoldMessenger.of(context).showSnackBar(snackBar);
                  } else {
                    AppKeys.NAVIGATOR_KEY.currentState?.popUntil(
                      (route) =>
                          route.settings.name == ItemLocatePage.routeName,
                    );
                  }
                },
              ),
            ],
            child: Scaffold(
              appBar: AppBar(
                leading: IconButton(
                  icon: Icon(Icons.arrow_back),
                  onPressed: () {
                    _clearAllItemsInList();
                    AppKeys.NAVIGATOR_KEY.currentState?.pushNamedAndRemoveUntil(
                        HomePage.routeName, (route) => false);
                  },
                ),
                title: Text(
                    'Locate item ${context.read<ItemBarcodeCubit>().state}'),
                centerTitle: true,
              ),
              floatingActionButton: Padding(
                padding: const EdgeInsets.only(bottom: 40, right: 20),
                child: FloatingActionButton(
                  onPressed: () => scanBarcodeNormal(dropdownValue),
                  child: Icon(
                    const IconData(0xefe1, fontFamily: 'MaterialIcons'),
                    size: 35.0,
                  ),
                  backgroundColor: Color(0xff33691e),
                  foregroundColor: Colors.white,
                ),
              ),
              body: Center(
                child: Form(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: [
                      SizedBox(
                        height: 20,
                      ),
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: DropdownButtonFormField<ViewItem>(
                          decoration: InputDecoration(
                            filled: true,
                            labelText: 'Item',
                          ),
                          value: dropdownValue,
                          icon: const Icon(Icons.arrow_downward),
                          elevation: 16,
                          items: context
                              .read<ViewItemCubit>()
                              .state
                              .viewItems
                              ?.map<DropdownMenuItem<ViewItem>>(
                            (item) {
                              return DropdownMenuItem<ViewItem>(
                                value: item,
                                child: Text(
                                  '${item.itemId}. ${item.materialNumber} ${item.materialDescription}',
                                ),
                              );
                            },
                          ).toList(),
                          onChanged: (ViewItem? newValue) {
                            _clearAllItemsInList();
                            context.read<ViewItemFormCubit>().set(newValue!);
                          },
                        ),
                      ),
                      BlocBuilder<AssigmentItemsCubit, AssigmentItemsState>(
                        builder: (context, state) {
                          return Expanded(
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.start,
                              children: [
                                Container(
                                  decoration: BoxDecoration(
                                    color: Colors.white,
                                    borderRadius:
                                        BorderRadius.all(Radius.circular(5)),
                                    boxShadow: [
                                      BoxShadow(
                                        color: Colors.grey.withOpacity(0.2),
                                        spreadRadius: 5,
                                        blurRadius: 15,
                                        offset: Offset(0, 10),
                                      ),
                                    ],
                                  ),
                                  child: dropdownValue != null
                                      ? Text(
                                          'Left to assign: ${dropdownValue.totalQuantity - dropdownValue.assignedQuantity - context.read<AssigmentItemsCubit>().state.items.fold(
                                                0,
                                                (acc, item) {
                                                  return acc   item!.quantity;
                                                },
                                              )}',
                                          style: TextStyle(fontSize: 20),
                                        )
                                      : Text(''),
                                ),
                                AssigmentItems(
                                  locationListKey: locate_list_key,
                                ),
                              ],
                            ),
                          );
                        },
                      ),
                      ElevatedButton(
                        onPressed: () {
                          final assignments =
                              context.read<AssigmentItemsCubit>().state.items;
                          context
                              .read<AssignmentCubit>()
                              .postAssignment(assignments);
                          _clearAllItemsInList();
                        },
                        child: Text('Save'),
                      )
                    ],
                  ),
                ),
              ),
            ),
          );
        },
      ),
    );

CodePudding user response:

Based on the comments I just moved the things around, placed MultiBlocListener as the "root" and BlocBuilder as the MultiBlocListener's child

@override
Widget build(BuildContext context) {
  return WillPopScope(
    onWillPop: () {
      AppKeys.NAVIGATOR_KEY.currentState?.pushNamedAndRemoveUntil(
        HomePage.routeName,
        (route) => false,
      );
      return Future.value(true);
    },
    child: MultiBlocListener(
      listeners: [
        BlocListener<ViewItemCubit, ViewItemState>(
          listener: (context, state) {
            if (state.status.isLoading) {
              AppKeys.NAVIGATOR_KEY.currentState?.pushNamed(
                SplashPage.routeName,
              );
            } else {
              AppKeys.NAVIGATOR_KEY.currentState?.popUntil(
                (route) =>
                    route.settings.name == ItemLocatePage.routeName,
              );
            }
          },
        ),
        BlocListener<AssignmentCubit, AssignmentState>(
          listener: (context, state) async {
            print('AssignmentCubit-------------->: $state');
            if (state.status.isPosting) {
              AppKeys.NAVIGATOR_KEY.currentState?.pushNamed(
                SplashPage.routeName,
              );
            }
            if (state.status.isSuccess) {
              await context.read<ViewItemCubit>().fetchViewItems(
                    int.parse(
                      context.read<ItemBarcodeCubit>().state,
                    ),
                  );
              final snackBar = SnackBar(
                duration: Duration(seconds: 2),
                content: Text('added'),
                backgroundColor: Colors.green,
              );
              ScaffoldMessenger.of(context).showSnackBar(snackBar);
            } else {
              AppKeys.NAVIGATOR_KEY.currentState?.popUntil(
                (route) =>
                    route.settings.name == ItemLocatePage.routeName,
              );
            }
          },
        ),
      ],
      child: BlocBuilder<ViewItemFormCubit, ViewItem?>(
        builder: (context, state) {
          final dropdownValue =
              context.read<ViewItemFormCubit>().state == ViewItem.empty()
                  ? null
                  : context.read<ViewItemFormCubit>().state;
          return Scaffold(
              appBar: AppBar(
                leading: IconButton(
                  icon: Icon(Icons.arrow_back),
                  onPressed: () {
                    _clearAllItemsInList();
                    AppKeys.NAVIGATOR_KEY.currentState?.pushNamedAndRemoveUntil(
                        HomePage.routeName, (route) => false);
                  },
                ),
                title: Text(
                    'Locate item ${context.read<ItemBarcodeCubit>().state}'),
                centerTitle: true,
              ),
              floatingActionButton: Padding(
                padding: const EdgeInsets.only(bottom: 40, right: 20),
                child: FloatingActionButton(
                  onPressed: () => scanBarcodeNormal(dropdownValue),
                  child: Icon(
                    const IconData(0xefe1, fontFamily: 'MaterialIcons'),
                    size: 35.0,
                  ),
                  backgroundColor: Color(0xff33691e),
                  foregroundColor: Colors.white,
                ),
              ),
              body: Center(
                child: Form(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: [
                      SizedBox(
                        height: 20,
                      ),
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: DropdownButtonFormField<ViewItem>(
                          decoration: InputDecoration(
                            filled: true,
                            labelText: 'Item',
                          ),
                          value: dropdownValue,
                          icon: const Icon(Icons.arrow_downward),
                          elevation: 16,
                          items: context
                              .read<ViewItemCubit>()
                              .state
                              .viewItems
                              ?.map<DropdownMenuItem<ViewItem>>(
                            (item) {
                              return DropdownMenuItem<ViewItem>(
                                value: item,
                                child: Text(
                                  '${item.itemId}. ${item.materialNumber} ${item.materialDescription}',
                                ),
                              );
                            },
                          ).toList(),
                          onChanged: (ViewItem? newValue) {
                            _clearAllItemsInList();
                            context.read<ViewItemFormCubit>().set(newValue!);
                          },
                        ),
                      ),
                      BlocBuilder<AssigmentItemsCubit, AssigmentItemsState>(
                        builder: (context, state) {
                          return Expanded(
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.start,
                              children: [
                                Container(
                                  decoration: BoxDecoration(
                                    color: Colors.white,
                                    borderRadius:
                                        BorderRadius.all(Radius.circular(5)),
                                    boxShadow: [
                                      BoxShadow(
                                        color: Colors.grey.withOpacity(0.2),
                                        spreadRadius: 5,
                                        blurRadius: 15,
                                        offset: Offset(0, 10),
                                      ),
                                    ],
                                  ),
                                  child: dropdownValue != null
                                      ? Text(
                                          'Left to assign: ${dropdownValue.totalQuantity - dropdownValue.assignedQuantity - context.read<AssigmentItemsCubit>().state.items.fold(
                                                0,
                                                (acc, item) {
                                                  return acc   item!.quantity;
                                                },
                                              )}',
                                          style: TextStyle(fontSize: 20),
                                        )
                                      : Text(''),
                                ),
                                AssigmentItems(
                                  locationListKey: locate_list_key,
                                ),
                              ],
                            ),
                          );
                        },
                      ),
                      ElevatedButton(
                        onPressed: () {
                          final assignments =
                              context.read<AssigmentItemsCubit>().state.items;
                          context
                              .read<AssignmentCubit>()
                              .postAssignment(assignments);
                          _clearAllItemsInList();
                        },
                        child: Text('Save'),
                      )
                    ],
                  ),
                ),
              ),
            ),
        })
    );
  )
}

CodePudding user response:

I solved this by code:

BlocListener<AssignmentCubit, AssignmentState>(
            listener: (context, state) async {
              print('AssignmentCubit-------------->: $state');
              if (state.status.isPosting) {
                AppKeys.NAVIGATOR_KEY.currentState?.pushReplacementNamed(
                  SplashPage.routeName,
                );
              }
              if (state.status.isSuccess) {
                await context.read<ViewItemCubit>().fetchViewItems(
                      int.parse(
                        context.read<ItemBarcodeCubit>().state,
                      ),
                    );
                final snackBar = SnackBar(
                  duration: Duration(seconds: 2),
                  content: Text('added'),
                  backgroundColor: Colors.green,
                );
                ScaffoldMessenger.of(context).showSnackBar(snackBar);
              }
              if (state.status.isInitial) {
                AppKeys.NAVIGATOR_KEY.currentState?.pushNamed(
                  ItemLocatePage.routeName,
                );
              }
            },
          ),
  • Related