pottery 0.0.1+2 copy "pottery: ^0.0.1+2" to clipboard
pottery: ^0.0.1+2 copied to clipboard

A widget to limit the scope where particular Pots are available in the widget tree.

Pub Version pottery CI codecov

Overview #

Pottery is a widget that limits the scope where particular Pots are available in the widget tree. Using it makes it clearer from which point onwards pots are used.

Why is this better than scoping by Pot itself? #

The scoping feature of Pot is not very suitable for Flutter apps because Pot is not a package specific to Flutter but for Dart in general and so is the scoping feature.

Pottery makes use of the widget lifecycle to limit the scope of pots. It is more natural in Flutter and less error-prone.

How beneficial is it to use this? #

It is convenient that you can access a pot stored in a global variable from anywhere, but it gives you too much freedom, making it difficult to keep the architecture of your app well-organised.

By using Pottery, it becomes possible to manage pots in a similar manner to using package:provider. See the example described later in this document.

Getting started #

This package contains the pot package and exposes it. It is enough to only add pottery without pot to pubspec.yaml.

dependencies:
  pottery: ^x.x.x

Usage #

Create a pot as pending if the pot is not necessary at the beginning of an app.

final counterNotifierPot = Pot.pending<CounterNotifier>();

Use Pottery and specify a factory right before you need to use the pot.

Widget build(BuildContext context) {
  // counterNotifierPot does not have a factory yet.
  // Calling `counterNotifierPot()` here throws a PotNotReadyException.

  ...

  return Scaffold(
    body: Pottery(
      pots: {
        counterNotifierPot: CounterNotifier.new,
      },
      // The new factory specified in the pots argument above is ready
      // before this builder is called for the first time.
      builder: (context) {
        // Methods and getters of counterNotifierPot are now available.
        final count = counterNotifierPot();
        ...
      },
    ),
  ),
);

The factory of each of the pot passed to the pots argument as a key in the map becomes ready with the new factory passed as a value, and it makes the pots available from that point onwards.

It is easier to understand how to use Pottery if you take it as similar to the usage of MultiProvider of the provider package, although what they do are quite different in fact.

  • MultiProvider
    • Creates objects and provides them so that they are available down the tree.
  • Pottery
    • Replaces factories to make pots ready so that they are available after that point.

Removing Pottery (e.g. navigating back from the page where Pottery is used) resets all pots passed to the pots argument and replaces their factories to throw an PotNotReadyException.

Caveats #

Make sure to specify a factory that returns a correct type. #

The pots argument is not type-safe as it uses a generic Map.

final counterNotifierPot = Pot.pending<CounterNotifier>();
pots: {
  counterNotifierPot: TodoNotifier.new,
}

In this example, the factory of counterNotifierPot must be a function that returns CounterNotifier. However, the static analysis does not tell you it is wrong to specify a factory that creates TodoNotifier. The error only occurs at runtime.

Usage with Grab #

The author created Pot and Pottery mainly for using them in combination with Grab. You can use Pottery + Grab as an alternative to package:provider.

There is however an important thing to remember. The extension methods of Grab require the BuildContext of the widget in which they are used, not the one passed to the builder function of Pottery.

class MyWidget extends StatelessWidget with Grab {
  const MyWidget();

  @override
  Widget build(BuildContext context) {
    return Pottery(
      pots: { ... },
      builder: (context) {
        // It is not possible to use the BuildContext passed to
        // this callback to call grab extension methods on.
        final count = context.grab<int>(counterNotifierPot());
      },
    )
  }
}

Tt is actually possible to get around it by using the outer BuildContext instead.

Widget build(BuildContext context) {
  return Pottery(
    pots: { ... },
    builder: (innerContext) {
      // Grab works if you use the `context` passed to
      // the build method instead of `innerContext`.
      final count = context.grab<int>(counterNotifierPot());
    },
  );
)

However, using grab methods this way is discouraged as it is confusing and can easily lead to a bug. If you are using grab_lints, it will warn you about it.

Make sure to use Pottery a little earlier to get pots ready before they are used in a build method. Here are two options for it.

Option 1 #

Using Pottery in the builder function of PageRoute before navigation.

ElevatedButton(
  onPressed: () => Navigator.of(context).push(
    MaterialPageRoute<void>(
      builder: (_) => Pottery(
        pots: { ... },
        builder: (_) => const CounterPage(),
      ),
    ),
  ),
  child: const Text('To CounterPage'),
)

Option 2 #

Using Pottery in the builder function of PageRoute in a route method.

This is essentially the same as Option 1, but more recommended because Pottery is used in the class of the actual page where pots are used. It makes more sense and helps you easily grasp the scope of pots when you get back to the code after a long while.

class CounterPage extends StatelessWidget {
  const CounterPage._();

  static Route<void> route() {
    return MaterialPageRoute(
      builder: (_) => Pottery(
        pots: { ... },
        builder: (_) => const CounterPage._(),
      ),
    );
  }

  Widget build(BuildContext context) {
    final count = context.grab<int>(counterNotifierPot());
  }
}
ElevatedButton(
  onPressed: () => Navigator.of(context).push(CounterPage.route()),
  child: const Text('To CounterPage'),
)
2
likes
0
pub points
49%
popularity

Publisher

verified publisherkaboc.cc

A widget to limit the scope where particular Pots are available in the widget tree.

Repository (GitHub)
View/report issues

License

unknown (LICENSE)

Dependencies

flutter, pot

More

Packages that depend on pottery