Emiting a change state in my cubit doesn't produce an event for my listener

Viewed 4455

My screen looks like this:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:app/flows/splashscreen/splash_screen_cubit.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:rflutter_alert/rflutter_alert.dart';

class SplashScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocConsumer<SplashScreenCubit, SplashScreenState>(
        listener: (context, state) {
      debugPrint("listener received something");
      if (state is SplashScreenCheckingToken) {
        debugPrint("state is SplashScreenCheckingToken");
        context.bloc<SplashScreenCubit>().checkingAccessToken();
      } else if (state is SplashScreenTokenValid) {
        Navigator.pushNamed(context, '/home');
      } else if (state is SplashScreenTokenInvalid) {
        Navigator.pushNamed(context, '/landing-page');
      } else if (state is SplashScreenError) {
        _showError(context);
      }
    }, builder: (context, state) {
      if (state is SplashScreenInitial) {
        debugPrint("state is SplashScreenInitial");
        context
            .bloc<SplashScreenCubit>()
            .checkAccessToken(); // doesn't work, but why?
        // context.bloc<SplashScreenCubit>().checkingAccessToken(); // works
        return Scaffold(
            body:
                Container(color: Colors.green, child: _loadingWidget(context)));
      } else {
        return Container();
      }
    });
  }

  SpinKitChasingDots _loadingWidget(BuildContext context) {
    return SpinKitChasingDots(
      color: Colors.white,
      size: 50.0,
    );
  }

  Future<bool> _showError(BuildContext context) {
    return Alert(context: context, title: "Error", desc: "Something went wrong")
        .show();
  }
}

My cubit like this:

import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'package:app/repository/api_repository.dart';
part 'splash_screen_state.dart';

class SplashScreenCubit extends Cubit<SplashScreenState> {
  final APIRepository _apiRepository;

  SplashScreenCubit(this._apiRepository) : super(SplashScreenInitial());

  void checkAccessToken() {
    debugPrint("checkAccessToken begin");
    emit(SplashScreenCheckingToken());
    debugPrint("checkAccessToken finished");
  }

  Future<void> checkingAccessToken() async {
    try {
      final quote = await _apiRepository.fetchQuote();
      debugPrint(quote.toString());
      emit(SplashScreenTokenValid());
    } on Error {
      emit(SplashScreenError());
    }
  }

  void accessTokenValid() {
    emit(SplashScreenTokenValid());
  }

  void accessTokenInvalid() {
    emit(SplashScreenTokenInvalid());
  }
}

And my states look as follows:

part of 'splash_screen_cubit.dart';

enum SplashScreenStateEnum {
  Initial,
  CheckingToken,
  TokenValid,
  TokenInvalid,
  Error,
}

abstract class SplashScreenState {
  final SplashScreenStateEnum splashScreenStateEnum;

  const SplashScreenState(this.splashScreenStateEnum);
}

class SplashScreenInitial extends SplashScreenState {
  const SplashScreenInitial() : super(SplashScreenStateEnum.Initial);
}

class SplashScreenCheckingToken extends SplashScreenState {
  const SplashScreenCheckingToken()
      : super(SplashScreenStateEnum.CheckingToken);

  @override
  bool operator ==(Object o) {
    if (identical(this, o)) return true;

    return o is SplashScreenCheckingToken &&
        o.splashScreenStateEnum == splashScreenStateEnum;
  }

  @override
  int get hashCode => splashScreenStateEnum.hashCode;
}

class SplashScreenTokenValid extends SplashScreenState {
  const SplashScreenTokenValid() : super(SplashScreenStateEnum.TokenValid);

  @override
  bool operator ==(Object o) {
    if (identical(this, o)) return true;

    return o is SplashScreenTokenValid &&
        o.splashScreenStateEnum == splashScreenStateEnum;
  }

  @override
  int get hashCode => splashScreenStateEnum.hashCode;
}

class SplashScreenTokenInvalid extends SplashScreenState {
  const SplashScreenTokenInvalid() : super(SplashScreenStateEnum.TokenInvalid);

  @override
  bool operator ==(Object o) {
    if (identical(this, o)) return true;

    return o is SplashScreenTokenInvalid &&
        o.splashScreenStateEnum == splashScreenStateEnum;
  }

  @override
  int get hashCode => splashScreenStateEnum.hashCode;
}

class SplashScreenError extends SplashScreenState {
  const SplashScreenError() : super(SplashScreenStateEnum.Error);

  @override
  bool operator ==(Object o) {
    if (identical(this, o)) return true;

    return o is SplashScreenError &&
        o.splashScreenStateEnum == splashScreenStateEnum;
  }

  @override
  int get hashCode => splashScreenStateEnum.hashCode;
}

When I run the program the following gets printed:

flutter: state is SplashScreenInitial
flutter: checkAccessToken begin
flutter: checkAccessToken finished

This means that despite the checkAccessToken() function in Cubit getting triggered no events in the listener of the BlocConsumer on the SplashScreen come in.

Otherwise it would've printed:

"listener received something"

I've no idea why, because when I try the checkingAccessToken() function in my Cubit this does produce events for the listener.

1 Answers

Your SplashScreenCheckingToken is responsible for all other "redirect" states but it's never triggered. Maybe what you can do is modify your cubit constructor after initialization to.

class SplashScreenCubit extends Cubit<SplashScreenState> {
  final APIRepository _apiRepository;

  SplashScreenCubit(this._apiRepository) : super(SplashScreenInitial()) {
    emit(SplashScreenCheckingToken());
  }

  ...
}

That should fix it.

Related