flutter share received pusher data between screens using Riverpod

Viewed 747

In our system we used Pusher on both of our Admin Panel and mobile application, in flutter i want to wrap whole application screens with Pusher and Riverpod and using providers with Hook widget in screens, that means i want to implement Pusher in main or MyApp and broadcast received data from Pusher on all of screens which we have them, basically we had to use Pusher in each screen which we need to receive data and its difficult to maintain application, for example:

enter image description here

this sample code is not correct and i tried to implement that, but i can't

here as you can see Pusher events and listeners work fine without any problem:

D/PusherClientPlugin( 7447): Event stream cancelled.
D/PusherClientPlugin( 7447): Event stream listening...
D/PusherClientPlugin( 7447): Event stream cancelled.
D/PusherClientPlugin( 7447): Event stream listening...
D/PusherClientPlugin( 7447): [BIND] new-login
D/PusherClientPlugin( 7447): Event stream cancelled.
D/PusherClientPlugin( 7447): Event stream listening...
D/PusherClientPlugin( 7447): Event stream cancelled.
D/PusherClientPlugin( 7447): Event stream listening...
D/PusherClientPlugin( 7447): [BIND] new-login
D/PusherClientPlugin( 7447): [ON_EVENT] Channel: backers-list, EventName: new-login,
D/PusherClientPlugin( 7447): Data: Sending Test Data , User Id: null
I/flutter ( 7447): received

SpashScreen class as initializing Pusher

class SplashScreen extends HookWidget{
  @override
  Widget build(BuildContext context) {
    _routeNavigation();
    final PusherClient pusher = PusherClient(
        "xxxx",
        PusherOptions(
        cluster: 'us2',
    ));
    final Channel channel;

    pusher.connect();

    channel = pusher.subscribe("backers-list");

    channel.bind("new-login", (event) {
      print('received');
      context
          .read(alarmNotificationStateProvider.notifier)
          .increment('${event?.data.toString()}');
    });

    return Scaffold(
      /* ... */

Profile screen should be receive data from Pusher which i implemented that into SplashScreen

class Profile extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final alarmNotification = useProvider(alarmNotificationStateProvider);
    print('PUSH RECEIVED');
    /* ... */
}

alarmNotificationStateProvider :

final alarmNotificationStateProvider = StateNotifierProvider<AlarmNotification, AlarmNotificationData>(
      (ref) => AlarmNotification(),
);

AlarmNotification class:

class AlarmNotification extends StateNotifier<AlarmNotificationData> {
  AlarmNotification() : super(_initialValue);

  static const _initialValue = AlarmNotificationData('');

  void increment(String data) {
    state = AlarmNotificationData(data);
  }
}

AlarmNotificationData class:

class AlarmNotificationData {
  final String data;

  const AlarmNotificationData(this.data);
}
5 Answers

To listen changes in riverpod you require useProvider(provider);

The useProvider method will listen for state changes in provider, which is the current instance of your model class

This also gives you a reference to the notifier state, which you’re storing in model class

use this:

final alarmNotificationNotifier  = useProvider(alarmNotificationProvider);

instead of final alarmNotificationNotifier = context.read(alarmNotificationProvider);

the read method gets you a reference to your state management class (CounterNotifier) without listening for changes in the state

I haven't seen your code of AlarmNotification, so I use a simple version below.

class AlarmNotification extends ChangeNotifier{    
  var _data;
  String get data => _data;

  void receivedData(String data){
    _data = data;
    notifyListeners();
  }
}

I think you misunderstand a little about riverpod. The MyApp seems only provide the event data but not consume it. So the part you can just use StatelessWidget.(It is also suggested to use "context.read(someProvider)" if you only read not watch)

final alarmNotificationProvider = ChangeNotifierProvider((ref)=>AlarmNotification());

class MyApp extends StatelessWidget{
  const MyApp({Key? key}):super(key: key);

  @override
  Widget build(BuildContext context) {

    ...

    channel.bind("new-login", (event) {
      context
          .read(alarmNotificationProvider)
          .receivedData('${event?.data.toString()}');
    });

    ...
  }
}

And the other widgets that need the data just listen to the alarmNotificationProvider (you may need to import the file to see it). It will rebuild the widget once it gets the notification.

class OtherWidget extends HookWidget {
  const OtherWidget({Key? key}):super(key: key);

  @override
  Widget build(BuildContext context) {
    final alarmNotification = useProvider(alarmNotificationProvider);
    
    return Text(alarmNotification.data);
  }
}

Try it this way,

/// Code

 runApp(
  MultiProvider(
   providers: [
     ChangeNotifierProvider<SettingsProvider>(
       create: (context) => SettingsProvider(),
     ),   
   ],
   child: MyApp(),
  ),
 );

///

class SettingsProvider extends ChangeNotifier {
  Locale _currentLocale = Locale("en", "");
  String _languageCode = "en";

  Locale get getCurrentLocale => _currentLocale;

  String get getLanguageCode => _languageCode;

  void updateLocale(Locale locale) {
    Log.loga(title, "updateLocale: >>>> $locale");
    Log.loga(title, "updateLocale: toLanguageTag >>>> ${locale.toLanguageTag()}");

    this._currentLocale = locale;
    AppTranslations.load(locale);
    this._languageCode = locale.toLanguageTag();

  //notifyListeners();
  Future.delayed(Duration(seconds: 0)).then((value) {
    super.notifyListeners();
  });
 }
}

/// update data
Provider.of<SettingsProvider>(context, listen: false).updateLocale(locale);

/// get data
Provider.of<SettingsProvider>(context).getCurrentLocale

make sure both screeens are under the changenotifier in widget tree,

other option is pass your provider to login screen as argument and use changenotifier.value() in login screen,

We are also using pusher. We are using flutter_pusher package and notifications work as expected. you can initialize it by e.g.

Pusher.init('API_KEY', PusherOptions(encrypted:true));
Related