0

I'am using PageView now. In the PageView, there are four pages.

class OnboardingScreen extends StatefulWidget {
  const OnboardingScreen({super.key});

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

class OnboardingScreenState extends State<OnboardingScreen> {
  late final List<Widget> _pages;
  double _progressRatio = 0.0;
  final PageController _pageController = PageController(
    initialPage: 0,
  );
  final OnboardingModel _onboardingData = OnboardingModel();

  void _syncProgressRatio() {
    if (!_pageController.hasClients) {
      _progressRatio = 0.0;
      return;
    }

    double currentPage = _pageController.page!;
    int totalPageCount = _pages.length - 1;
    _progressRatio = currentPage / totalPageCount;
  }

  void _goNextPage() async {
    await _pageController.nextPage(
      duration: const Duration(milliseconds: 1),
      curve: Curves.easeInOut,
    );
    setState(() {
      _syncProgressRatio();
    });
  }

  void _goPreviousPage() async {
    await _pageController.previousPage(
      duration: const Duration(milliseconds: 1),
      curve: Curves.easeInOut,
    );
    setState(() {
      _syncProgressRatio();
    });
  }

  void _onboardingFinish() {
    context.read<OnboardingBloc>().add(
          OnboardingFinished(
            nickName: _onboardingData.nickName!,
            genderType: _onboardingData.genderType!,
            birthday: _onboardingData.birthDay!,
            profileImage: _onboardingData.profileImage,
          ),
        );
  }

  @override
  void initState() {
    super.initState();
    DateTime today = DateTime.now();
    _onboardingData.birthDay =
        BirthdayModel(today.year, today.month, today.day);
    _pages = [
      OnboardingNickName(
        onboardingData: _onboardingData,
        goNextPage: _goNextPage,
      ),
      OnboardingGender(
        onboardingData: _onboardingData,
        goNextPage: _goNextPage,
        goPreviousPage: _goPreviousPage,
      ),
      OnboardingBirthday(
        onboardingData: _onboardingData,
        goNextPage: _goNextPage,
        goPreviousPage: _goPreviousPage,
      ),
      OnboardingProfileImage(
        onboardingData: _onboardingData,
        onboardingFinish: _onboardingFinish,
        goPreviousPage: _goPreviousPage,
      ),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        return false;
      },
      child: Scaffold(
        body: SafeArea(
          child: BlocListener<OnboardingBloc, OnboardingState>(
            listener: (context, state) {
              if (state is OnboardingSucceed) {
                print('OnboardingSucceed');
                context.goNamed(RouterLocation.onboardingComplete);
                return;
              }

              if (state is OnboardingFailed) {
                print('OnboardingFailed');
                BasicDialog.show(
                  context: context,
                  title: TextManager.onboardingFailedExceptionTitle.tr(),
                  contents: TextManager.onboardingFailedExceptionContents.tr(),
                  confirmAction: () {
                    context.read<OnboardingBloc>().add(
                          OnboardingFinished(
                            nickName: _onboardingData.nickName!,
                            genderType: _onboardingData.genderType!,
                            birthday: _onboardingData.birthDay!,
                            profileImage: _onboardingData.profileImage,
                          ),
                        );
                    Navigator.of(context).pop();
                  },
                );
              }
            },
            child: ProgressWrapper(
              child: Column(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  _buildProgressBar(_progressRatio),
                  Expanded(
                    child: Padding(
                      padding: const EdgeInsets.symmetric(
                          horizontal: ValueManager.s15),
                      child: PageView(
                        controller: _pageController,
                        physics: const NeverScrollableScrollPhysics(),
                        children: _pages,
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildProgressBar(double progressRatio) {
    return ProgressBar(
      progressRatio: progressRatio,
      height: ValueManager.s10,
    );
  }

  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }
}

in the last page, which is OnboardingProfileImage call method _onboardingFinish. and OnboardingBloc handle this.


class OnboardingBloc extends Bloc<OnboardingEvent, OnboardingState> {
  final LoadingSpinnerBloc loadingSpinnerBloc;
  final UserRepository userRepository;

  OnboardingBloc({
    required this.loadingSpinnerBloc,
    required this.userRepository,
  }) : super(OnboardingScreenLaunched()) {
    on<OnboardingFinished>((event, emit) async {
      loadingSpinnerBloc.processing();
      OnboardingCompleteCommand command = OnboardingCompleteCommand(
        nickName: event.nickName,
        genderType: event.genderType,
        birthDay: event.birthday,
        profileImage: event.profileImage,
      );
      try {
        final Either<AppException, void> response =
            await userRepository.onboardingComplete(command);

        response.fold((exception) {
          emit(OnboardingFailed(exception));
        }, (success) {
          emit(OnboardingSucceed());
        });
        loadingSpinnerBloc.finished();
      } catch (error) {
        emit(OnboardingFailed(AppException(error.toString())));
        loadingSpinnerBloc.failed();
      }
    });
  }
}

the problem is here, await userRepository.onboardingComplete(command);

Future<Either<AppException, void>> onboardingComplete(
      OnboardingCompleteCommand command) async {
    bool isConnected = await connectionManager.isConnected;
    if (!isConnected) {
      return Left(AppException(TextManager.internetNotConnected.tr()));
    }

    final Map<String, dynamic> jsonData = command.toJson();
    final FormData formData;
    if (command.profileImage != null) {
      formData = FormData.fromMap({
        'profileImage':
            await MultipartFile.fromFile(command.profileImage!.path),
      });

      jsonData.forEach((key, value) {
        formData.fields.add(MapEntry(key, value.toString()));
      });
    } else {
      formData = FormData.fromMap(jsonData);
    }

    try {
      
      // page index not changed
      // throw DioException(requestOptions: RequestOptions());

      // exception happen and page index changed to 0
      await apiClient.post(
        '/user/profile',
        data: formData,
        options: Options(
          contentType: 'multipart/form-data',
        ),
      );
      return const Right(null);
    } on DioException catch (error) {
      return Left(
          AppException(TextManager.onboardingFailedExceptionContents.tr()));
    }
  }

when DioException occured, pageView index is changed... catch statement is working. but pageView index is changed.

so I tested that throw DioException on purpose, then pageView index not changed.

what is wrong with dio? how can I maintain pageView index with this code?

maintain pageView index

0 Answers0