skip to Main Content

i am quite new with flutter. I am trying to add a ChangeNotifierProvider into my app. I use flutter_azure_b2c to log in a user, in order to handle to login outcome I have the following code:

AzureB2C.registerCallback(B2COperationSource.POLICY_TRIGGER_INTERACTIVE,
    (result) async {
  if (result.reason == B2COperationState.SUCCESS) {
    List<String>? subjects = await AzureB2C.getSubjects();

    if (subjects != null && subjects.isNotEmpty) {
      B2CAccessToken? token = await AzureB2C.getAccessToken(subjects[0]);
      if (!mounted || token == null) return;
      final encodedPayload = token.token.split('.')[1];
      final payloadData =
          utf8.fuse(base64).decode(base64.normalize(encodedPayload));
      final claims = Claims.fromJson(jsonDecode(payloadData));
      var m = Provider.of<LoginModel>(context);
      m.logIn(claims);
    }
  }
});

The problem is that when it arrives to var m = Provider.of<LoginModel>(context); the execution stops with out errors without executing m.logIn(claims);, so the model is not changed and the consumer is not called.

Any idea?

This is my consumer:

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => LoginModel(),
      child: MaterialApp(
          debugShowCheckedModeBanner: false,
          theme: appTheme,
          home: Consumer<LoginModel>(
            builder: (context, value, child) =>
                value.claims != null ? const Home() : const Login(),
          )),
    );
  }
}



class LoginModel extends ChangeNotifier {
  Claims? _claims;

  logIn(Claims claims) {
    _claims = claims;
    notifyListeners();
  }

  logOut() {
    _claims = null;
    notifyListeners();
  }

  Claims? get claims => _claims;
}

My LoginWidget:

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

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

class LoginState extends State<Login> {
  B2CConfiguration? _configuration;

  checkLogin(BuildContext context) async {
    List<String>? subjects = await AzureB2C.getSubjects();

    if (subjects != null && subjects.isNotEmpty) {
      B2CAccessToken? token = await AzureB2C.getAccessToken(subjects[0]);
      if (!mounted || token == null) return;
      final encodedData = token.token.split('.')[1];
      final data =
          utf8.fuse(base64).decode(base64.normalize(encodedData));
      final claims = Claims.fromJson(jsonDecode(data));
      var m = Provider.of<LoginModel>(context, listen: true);
      m.logIn(claims); //<-- debugger never reaches this line
    }
  }

  @override
  Widget build(BuildContext context) {
    // It is possible to register callbacks in order to handle return values
    // from asynchronous calls to the plugin
    AzureB2C.registerCallback(B2COperationSource.INIT, (result) async {
      if (result.reason == B2COperationState.SUCCESS) {
        _configuration = await AzureB2C.getConfiguration();
        if (!mounted) return;
        await checkLogin(context);
      }
    });

    AzureB2C.registerCallback(B2COperationSource.POLICY_TRIGGER_INTERACTIVE,
        (result) async {
      if (result.reason == B2COperationState.SUCCESS) {
        if (!mounted) return;
        await checkLogin(context);
      }
    });

    // Important: Remeber to handle redirect states (if you want to support
    // the web platform with redirect method) and init the AzureB2C plugin
    // before the material app starts.
    AzureB2C.handleRedirectFuture().then((_) => AzureB2C.init("auth_config"));

    const String assetName = 'assets/images/logo.svg';
    final Widget logo = SvgPicture.asset(
      assetName,
    );

    return SafeArea(
      child: //omitted,
    );
  }
}

I opened an issue as well, but it did not help me.

2

Answers


  1. Chosen as BEST ANSWER

    I fixed it, moving the callback registrations from the build method to the initState method.


  2. Try this
    var m = Provider.of<LoginModel>(context, listen: false)._claims;

    You are using the Provider syntax but not doing anything really with it. You need to set it like this Provider.of<LoginModel>(context, listen: false).login(claims) and call it like this Provider.of<LoginModel>(context, listen: false)._claims;

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search