vanshg395 / intl_phone_field

A customised Flutter TextFormField to input international phone number along with country code.
https://pub.dev/packages/intl_phone_field
MIT License
177 stars 507 forks source link

How to change initalCountryCode programmatically in a listview #300

Closed DEMONLEGENDARY closed 1 year ago

DEMONLEGENDARY commented 1 year ago

I have a ListView and its items are ExpansionPanel, each ExpansionPanel has a form, when I trigger an ordering method (filter) to the ListView data, all data is sorted correctly with it's own ExpansionPanel except for the InitialCountryCode value, at the first time I can bring a Country code value to InitialCountryCode but I can't change its value after. SetStates or Bloc's emits does not work on this. any example or idea on how to deal with this?

class StoresListView extends StatefulWidget {
  const StoresListView({
    super.key,
    required this.state,
    required this.parentContext,
    required this.filterTextFieldController,
    required this.phoneNumberTextFieldController,
    required this.storeLocationTextFieldController,
  });

  final ListViewState state;
  final BuildContext parentContext;
  final TextEditingController filterTextFieldController;
  final TextEditingController phoneNumberTextFieldController;
  final TextEditingController storeLocationTextFieldController;

  @override
  State<StoresListView> createState() => _StoresListViewState();
}

class _StoresListViewState extends State<StoresListView> {
  TextEditingController storeNameTextFieldController = TextEditingController();
  TextEditingController storeAddressTextFieldController =
      TextEditingController();
  List<TextEditingController>? phoneNumberTextFieldControllers;
  final RefreshController _refreshController = RefreshController();
  List<FocusNode>? storeNameFocusNodes;
  List<FocusNode>? storePhoneNumberFocusNodes;
  List<FocusNode>? storeAddressFocusNodes;

  @override
  Widget build(BuildContext context) {
    if (widget.state.dataHasAnError) {
      widget.parentContext.loaderOverlay.hide();
      return StoresListHasAnError(
        storesContext: widget.parentContext,
        refreshController: _refreshController,
        listViewState: widget.state,
      );
    } else if (widget.state.listViewData == null) {
      _refreshController.refreshCompleted();
      widget.parentContext.loaderOverlay.hide();
      return const Center(
          child: SizedBox(
              height: 300,
              width: 300,
              child: LoadingIndicator(
                indicatorType: Indicator.ballRotateChase,
                strokeWidth: 3.0,
              )));
    } else if (widget.state.noDataReason == NoDataReason.emptyResponse) {
      _refreshController.refreshCompleted();
      widget.parentContext.loaderOverlay.hide();
      return NoStoresFoundView(
        listViewState: widget.state,
      );
    } else {
      storeNameFocusNodes ??= widget.state.dbData!.map((e) {
        return FocusNode();
      }).toList();
      storePhoneNumberFocusNodes ??= widget.state.dbData!.map((e) {
        return FocusNode();
      }).toList();
      storeAddressFocusNodes ??= widget.state.dbData!.map((e) {
        return FocusNode();
      }).toList();
      phoneNumberTextFieldControllers ??= widget.state.dbData!.map((e) {
        return TextEditingController();
      }).toList();
      return SmartRefresher(
        controller: _refreshController,
        enablePullDown: true,
        onRefresh: () async {
          await widget.parentContext
              .read<StoresListViewCubit>()
              .getStores(true);
          widget.filterTextFieldController.clear();
        },
        child: ListView.separated(
          separatorBuilder: (context, index) {
            return Divider(
              color: Theme.of(context).colorScheme.secondaryContainer,
              thickness: 2,
              height: 0,
            );
          },
          itemCount: widget.state.listViewData!.length,
          itemBuilder: (context, index) {
            if (_refreshController.isRefresh) {
              _refreshController.refreshCompleted();
            }
            widget.parentContext.loaderOverlay.hide();
            return BlocProvider(
              create: (context) => ExpansionPanelFormCubit(),
              child:
                  BlocBuilder<ExpansionPanelFormCubit, ExpansionPanelFormState>(
                builder: (context, expansionPanelFormState) {
                  return SizedBox(
                    child: ExpansionPanelList(
                      expansionCallback: (panelIndex, isExpanded) {
                        for (int i = 0;
                            i < widget.state.expansionPanelExpandedList!.length;
                            i++) {
                          widget.state.expansionPanelExpandedList![i] = false;
                          widget.state.onEditModeOfEachExpansionPanel![i] =
                              false;
                        }
                        widget.state.expansionPanelExpandedList![index] =
                            !isExpanded;
                        storeNameTextFieldController.clear();
                        storeAddressTextFieldController.clear();
                        if (!widget
                            .state.onEditModeOfEachExpansionPanel![index]) {
                          context
                              .read<ExpansionPanelFormCubit>()
                              .revertFormzValues();
                        }
                        setState(() {});
                      },
                      animationDuration: const Duration(milliseconds: 750),
                      children: [
                        ExpansionPanel(
                          backgroundColor: Theme.of(widget.parentContext)
                              .colorScheme
                              .onPrimaryContainer,
                          headerBuilder: (context, isExpanded) {
                            return ExpansionPanelHeader(
                              storesContext: widget.parentContext,
                              state: widget.state,
                              index: index,
                            );
                          },
                          canTapOnHeader: true,
                          isExpanded:
                              widget.state.expansionPanelExpandedList![index],
                          body: Padding(
                              padding: const EdgeInsets.symmetric(
                                  vertical: 10, horizontal: 10),
                              child: Column(
                                children: <Widget>[
                                  Column(
                                    crossAxisAlignment:
                                        CrossAxisAlignment.start,
                                    children: <Widget>[
                                      Padding(
                                        padding:
                                            const EdgeInsets.only(bottom: 2),
                                        child: NameText(
                                            storesContext:
                                                widget.parentContext),
                                      ),
                                      AbsorbPointer(
                                        absorbing: !widget.state
                                                .onEditModeOfEachExpansionPanel![
                                            index],
                                        child: StoreNameTextField(
                                          storesContext: context,
                                          listViewState: widget.state,
                                          index: index,
                                          storeNameTextFieldController:
                                              storeNameTextFieldController,
                                          expansionPanelFormState:
                                              expansionPanelFormState,
                                          textFieldFocusNode:
                                              storeNameFocusNodes![index],
                                        ),
                                      ),
                                      Padding(
                                        padding: const EdgeInsets.only(
                                            bottom: 2, top: 8),
                                        child: PhoneNumberText(
                                            storesContext:
                                                widget.parentContext),
                                      ),
                                      AbsorbPointer(
                                        absorbing: !widget.state
                                                .onEditModeOfEachExpansionPanel![
                                            index],
                                        child: PhoneNumberTextField(
                                          phoneNumberTextFieldController:
                                              phoneNumberTextFieldControllers![
                                                  index],
                                          listViewState: widget.state,
                                          index: index,
                                          expansionPanelFormstate:
                                              expansionPanelFormState,
                                          focusNode:
                                              storePhoneNumberFocusNodes![
                                                  index],
                                          onEditModeOfEachExpansionPanel: widget
                                                  .state
                                                  .onEditModeOfEachExpansionPanel![
                                              index],
                                        ),
                                      ),
                                      AddressText(
                                          storesContext: widget.parentContext),
                                      Row(
                                        children: [
                                          Expanded(
                                            child: AbsorbPointer(
                                              absorbing: !widget.state
                                                      .onEditModeOfEachExpansionPanel![
                                                  index],
                                              child: AddressTextField(
                                                storesContext:
                                                    widget.parentContext,
                                                storeAddressTextFieldController:
                                                    storeAddressTextFieldController,
                                                index: index,
                                                expansionPanelFormState:
                                                    expansionPanelFormState,
                                                listViewState: widget.state,
                                                focusNode:
                                                    storeAddressFocusNodes![
                                                        index],
                                              ),
                                            ),
                                          ),
                                          AbsorbPointer(
                                            absorbing: !widget.state
                                                    .onEditModeOfEachExpansionPanel![
                                                index],
                                            child: MapIconButton(
                                                expansionPanelContext: context,
                                                storeAddressTextFieldController:
                                                    storeAddressTextFieldController),
                                          )
                                        ],
                                      ),
                                      Padding(
                                        padding:
                                            const EdgeInsets.only(bottom: 6),
                                        child: Row(
                                          children: [
                                            ActiveText(
                                                storesContext:
                                                    widget.parentContext),
                                            Padding(
                                              padding: const EdgeInsets.only(
                                                  left: 5),
                                              child: AbsorbPointer(
                                                  absorbing: !widget.state
                                                          .onEditModeOfEachExpansionPanel![
                                                      index],
                                                  child: SwitchButton(
                                                    storesContext:
                                                        widget.parentContext,
                                                    listViewState: widget.state,
                                                    index: index,
                                                    expansionPanelFormState:
                                                        expansionPanelFormState,
                                                  )),
                                            ),
                                          ],
                                        ),
                                      ),
                                      !widget.state
                                                  .onEditModeOfEachExpansionPanel![
                                              index]
                                          ? Row(
                                              mainAxisAlignment:
                                                  MainAxisAlignment.center,
                                              crossAxisAlignment:
                                                  CrossAxisAlignment.center,
                                              children: [
                                                EditButton(
                                                  storesContext:
                                                      widget.parentContext,
                                                  listViewState: widget.state,
                                                  index: index,
                                                  storeNameTextFieldController:
                                                      storeNameTextFieldController,
                                                  expansionPanelFormState:
                                                      expansionPanelFormState,
                                                  storeAddressTextFieldController:
                                                      storeAddressTextFieldController,
                                                  storePhoneNumberTextFieldController:
                                                      phoneNumberTextFieldControllers![
                                                          index],
                                                )
                                              ],
                                            )
                                          : Row(
                                              mainAxisAlignment:
                                                  MainAxisAlignment.center,
                                              crossAxisAlignment:
                                                  CrossAxisAlignment.center,
                                              children: [
                                                CancelButton(
                                                  storesContext: context,
                                                  storeNameTextFieldController:
                                                      storeNameTextFieldController,
                                                  index: index,
                                                  focusNode:
                                                      storeNameFocusNodes![
                                                          index],
                                                  storeAddressTextFieldFieldController:
                                                      storeAddressTextFieldController,
                                                  storePhoneNumberTextFieldController:
                                                      phoneNumberTextFieldControllers![
                                                          index],
                                                  listViewState: widget.state,
                                                ),
                                                const SizedBox(
                                                  width: 10,
                                                ),
                                                AcceptButton(
                                                    storesContext:
                                                        widget.parentContext,
                                                    index: index,
                                                    expansionPanelFormState:
                                                        expansionPanelFormState,
                                                    refreshController:
                                                        _refreshController)
                                              ],
                                            )
                                    ],
                                  ),
                                ],
                              )),
                        )
                      ],
                    ),
                  );
                },
              ),
            );
          },
        ),
      );
    }
  }
}

class PhoneNumberTextField extends StatelessWidget {
  const PhoneNumberTextField(
      {super.key,
      required this.phoneNumberTextFieldController,
      required this.listViewState,
      required this.index,
      required this.expansionPanelFormstate,
      required this.focusNode,
      required this.onEditModeOfEachExpansionPanel});
  final TextEditingController phoneNumberTextFieldController;
  final ListViewState listViewState;
  final ExpansionPanelFormState expansionPanelFormstate;
  final bool onEditModeOfEachExpansionPanel;
  final int index;
  final FocusNode focusNode;

  @override
  Widget build(BuildContext context) {
    if (!onEditModeOfEachExpansionPanel) {
      Future.delayed(Duration.zero, () {
        phoneNumberTextFieldController.text =
            listViewState.phoneNumbersList![index];
      });
    }
    return IntlPhoneField(
      focusNode: focusNode,
      initialValue: listViewState.listViewData![index].phone,
      decoration: InputDecoration(
        contentPadding: const EdgeInsets.symmetric(
          horizontal: 15,
        ),
        filled: true,
        fillColor: Theme.of(context).colorScheme.secondaryContainer,
        hintStyle: TextStyle(
          color: Theme.of(context).colorScheme.onPrimaryContainer,
        ),
        hintText: LocaleKeys.phoneNumber.tr(),
        border: OutlineInputBorder(
          borderRadius: const BorderRadius.all(
            Radius.circular(
              30,
            ),
          ),
          borderSide: BorderSide(
            color: Theme.of(context).colorScheme.primary,
          ),
        ),
        focusedBorder: OutlineInputBorder(
          borderRadius: const BorderRadius.all(
            Radius.circular(
              30,
            ),
          ),
          borderSide: BorderSide(
            color: Theme.of(context).colorScheme.primary,
            width: 1.8,
          ),
        ),
        errorBorder: OutlineInputBorder(
          borderSide: BorderSide(
            color: Theme.of(context).colorScheme.error,
            width: 2,
          ),
          borderRadius: const BorderRadius.all(
            Radius.circular(
              30,
            ),
          ),
        ),
        focusedErrorBorder: OutlineInputBorder(
          borderSide: BorderSide(
            color: Theme.of(context).colorScheme.error,
            width: 2,
          ),
          borderRadius: const BorderRadius.all(
            Radius.circular(
              30,
            ),
          ),
        ),
        floatingLabelBehavior: FloatingLabelBehavior.never,
      ),
      initialCountryCode: dotenv.get("baseCountry"),
      onChanged: (phoneNumber) async {
        await PhoneNumberUtil.isValidPhoneNumber(
                    phoneNumber.completeNumber, phoneNumber.countryCode) ==
                true
            ? context.read<ExpansionPanelFormCubit>().phoneNumberChanged(
                  phoneNumber.completeNumber,
                  true,
                )
            : context.read<ExpansionPanelFormCubit>().phoneNumberChanged(
                  phoneNumber.completeNumber,
                  false,
                );
      },
      onCountryChanged: (country) {
        context
            .read<ExpansionPanelFormCubit>()
            .onCountryChanged(country, listViewState.phoneNumbersList![index]);
      },
      inputFormatters: [FilteringTextInputFormatter.digitsOnly],
      controller: phoneNumberTextFieldController,
    );
  }
}

In this way I execute the sorting methods

class ListViewFilter extends StatefulWidget {
  const ListViewFilter(
      {Key? key,
      required this.parentContext,
      required this.filterTextFieldController,
      required this.runFilter,
      required this.orderListViewData})
      : super(key: key);
  final Function(String) runFilter;
  final Function(bool) orderListViewData;

  final BuildContext parentContext;
  final TextEditingController filterTextFieldController;

  @override
  State<ListViewFilter> createState() => _ListViewFilterState();
}

class _ListViewFilterState extends State<ListViewFilter> {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Expanded(
          child: TextField(
            controller: widget.filterTextFieldController,
            onChanged: (enteredKeyword) => widget.runFilter(enteredKeyword),
            decoration: InputDecoration(
                labelText: LocaleKeys.search.tr(),
                suffixIcon: const Icon(Icons.search),
                contentPadding: const EdgeInsets.all(10)),
          ),
        ),
        Center(
          child: PopupMenuButton(
            elevation: 10,
            tooltip: LocaleKeys.filters.tr(),
            position: PopupMenuPosition.under,
            itemBuilder: ((context) => [
                  PopupMenuItem(
                      onTap: () => widget.orderListViewData(true),
                      child: Row(
                        children: [
                          const Icon(
                            Icons.align_horizontal_left_rounded,
                            color: Colors.black54,
                          ),
                          Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: Text(LocaleKeys.byNameAZ.tr()),
                          )
                        ],
                      )),
                  PopupMenuItem(
                      onTap: () => widget.orderListViewData(false),
                      child: Row(
                        children: [
                          const Icon(
                            Icons.align_horizontal_left_rounded,
                            color: Colors.black54,
                          ),
                          Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: Text(LocaleKeys.byNameZA.tr()),
                          )
                        ],
                      )),
                ]),
          ),
        )
      ],
    );
  }
}
ArpitSharma7898 commented 1 year ago

is there any solution for this one?

github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs within the next 5 days. If you believe this issue is still relevant, please comment to keep it open. Thank you for your contributions.

debovitch commented 10 months ago

You can add a key: UniqueKey() to your IntlPhoneField widget, it will force to pass in the initState again.