felangel / bloc

A predictable state management library that helps implement the BLoC design pattern
https://bloclibrary.dev
MIT License
11.79k stars 3.39k forks source link

Pass extern Bloc in onGenerateRoute #916

Closed FTholin closed 4 years ago

FTholin commented 4 years ago

Dear Bloc community

I contact you because I'm facing to an important architecture question.

MyApp has onGenerateRoute method and I'm trying to centralize all navigations process in my Application.

onGenerateRoute: (settings) {
if (settings.name == "/test") {
  final ScreenArguments args = settings.arguments;

          return PageRouteBuilder(
            pageBuilder: (_, __, ___) => BlocProvider.value(
              // here
              value: args.myBloc,
              child: Screen(),
            ),
          );
        }
}

In following the bloc architecture is it correct to pass an extern bloc like in my code example or is it a bad way and I don't need to centralize all navigation elements ?

Thanks for your precious time

Best regards

felangel commented 4 years ago

Hi @FTholin 👋 Thanks for opening an issue!

I would recommend scoping the bloc to the route instead of passing it as an argument.

return PageRouteBuilder(
  pageBuilder: (_, __, ___) => BlocProvider(
    create: (_) => MyBloc(),
    child: Screen(),
  ),
);

Hope that helps!

FTholin commented 4 years ago

Thanks

omidraha commented 4 years ago

I would like to have reusable function, Let's call it showBlocPage to show a new material page route by having bloc. So I can call it several times like this:


class SampleWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        RaisedButton(
          child: Text('Button A'),  
          onPressed: () {
            // reusable function
            showBlocPage(
              context: context,
              child: Container(
                color: Colors.red,
              ),
              bloc: SampleBloc,
            );
          },
        ),
        RaisedButton(
          child: Text('Button B'),
          onPressed: () {
           // reusable function
            showBlocPage(
              context: context,
              child: Container(
                color: Colors.blue,
              ),
              bloc: SampleBloc,
            );
          },
        ),
      ],
    );
  }
}

I tried something like this :

void showBlocPage({
  BuildContext context,
  Widget child,
  Type bloc,
}) {
  Navigator.of(context).push(
    PageRouteBuilder<Null>(
      fullscreenDialog: true,
      opaque: false,
      barrierDismissible: true,
      transitionsBuilder: (
        BuildContext context,
        Animation<double> animation,
        Animation<double> secondaryAnimation,
        Widget child,
      ) {
        return SlideTransition(
          position: Tween<Offset>(
            begin: const Offset(0.0, 1.0),
            end: Offset.zero,
          ).animate(animation),
          child: child, // child is the value returned by pageBuilder
        );
      },
      pageBuilder: (BuildContext _context, _, __) {
       // I got error here for bloc
        return BlocProvider<bloc>.value(
          value: context.bloc<bloc>(),
          child: Material(
            type: MaterialType.transparency,
            child: SafeArea(
              child: child,
            ),
          ),
        );
      },
    ),
  );
}

But I got this syntax error: 'dynamic' doesn't extend 'Bloc<Object, Object>'.

narcodico commented 4 years ago

Hi @omidraha 👋

I believe this is what you're after:

void main() {
  runApp(
    BlocProvider<SampleBloc>(
      create: (_) => SampleBloc(),
      child: const MyApp(),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: SampleWidget(),
    );
  }
}

class SampleWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        RaisedButton(
          child: Text('Button A'),
          onPressed: () {
            // reusable function
            showBlocPage<SampleBloc>(
              context: context,
              child: Container(
                color: Colors.red,
              ),
            );
          },
        ),
        RaisedButton(
          child: Text('Button B'),
          onPressed: () {
            // reusable function
            showBlocPage<SampleBloc>(
              context: context,
              child: Container(
                color: Colors.blue,
              ),
            );
          },
        ),
      ],
    );
  }
}

void showBlocPage<T extends Bloc<Object, Object>>({
  BuildContext context,
  Widget child,
}) {
  Navigator.of(context).push(
    PageRouteBuilder<Null>(
      fullscreenDialog: true,
      opaque: false,
      barrierDismissible: true,
      transitionsBuilder: (
        BuildContext context,
        Animation<double> animation,
        Animation<double> secondaryAnimation,
        Widget child,
      ) {
        return SlideTransition(
          position: Tween<Offset>(
            begin: const Offset(0.0, 1.0),
            end: Offset.zero,
          ).animate(animation),
          child: child, // child is the value returned by pageBuilder
        );
      },
      pageBuilder: (BuildContext _context, _, __) {
        // I got error here for bloc
        return BlocProvider<T>.value(
          value: context.bloc<T>(),
          child: Material(
            type: MaterialType.transparency,
            child: SafeArea(
              child: child,
            ),
          ),
        );
      },
    ),
  );
}

Optionally you could use dynamic instead of Object, but up to you.