micha_core 0.3.3 copy "micha_core: ^0.3.3" to clipboard
micha_core: ^0.3.3 copied to clipboard

Extensions and widgets that are missing in Flutter's SDK.

Extensions and widgets that are missing in Flutter's SDK.

Features #

This package includes some extensions and widgets to help avoid imperative boilerplate by leaning on Flutter's declarative UI approach.

Other than that, the features in this package are mostly unrelated to each other.
It is just a collection of useful things that otherwise require boilerplate, like accessing BuildContext, and are typically needed in many projects.

Usage #

Separate items of collections #

Need to add some items between existing items of a List or Iterable? Use collection.separated(separator):

[1, 2, 3].separated(0); // [1, 0, 2, 0, 3]

Are these separators dependent on preceding and succeeding items? Use collection.separatedBy((before, after) => separator):

[1, 2, 3].separatedBy((before, after) => before + after); // [1, 3, 2, 5, 3]

Wrapper for Optional parameters #

Ever needed to differentiate the value of a nullable parameter that was purposefully passed as null from a value that was simply omitted?
For example copyWith should replace exactly those parameters that were passed. But how can it handle nullable parameters?

// status-quo, bad example
Foo copyWith({
  double? foo,
}) {
  return Foo(
    // The caller cannot raplce a non-null value of foo by null.
    foo: foo ?? this.foo,
  );
}

Flutter doesn't actually handle this case properly in their own classes, but we can do better by using the Wrapper type from this package:

Foo copyWith({
  Wrapper<double?>? foo,
}) {
  return Foo(
    // Applies any wrapped value of foo (including null).
    // Omit foo entirely and the old value is kept.
    foo: foo == null ? this.foo : foo.value,
  );
}

Any value can be wrapped by calling the wrapped getter on it:

fooInstance.copyWith(foo: 1.5.wrapped);

Find enum values "byNameOrNull" #

In dart, you can find enum values by their names, like:

enum TestEnum { one, two, three }

TestEnum.values.byName('two');

But what if that value does not exist? Dart will throw an ArgumentError. Use byNameOrNull to receive null instead:

TestEnum.values.byValueOrNull('four');

Gap #

We often require some small space between widgets. Flutter's widget catalog has limited options:

  • Flutter's Spacer takes up all available space, which is often more than we want.
  • Flutter's Padding unfortunately needs to be wrapped around widgets, adding boilerplate, while also being hard to read inside of lists.
  • The best that Flutter offers is a SizedBox with a specified width or height.
    However, this still has some problems: We need to set either width or height, depending on whether the SizedBox is placed inside a Row or Column.
    We also need to repeat the same constant pixel size all throughout the application.

Instead, consider using a Gap:

Column(
  children: [
    Text('first'),
    Gap(),
    Text('second'),
  ],
);

Gap takes up a fixed space in both directions.
It takes 16 pixels by default, but can be configured using the GapThemeData theme extension or its constructor parameters.
When you need a little more or less space relative to the configured theme, create a Gap with a scale factor, like Gap(scale: 2) or Gap(scale: 0.5) respectivly. You can also add to, subtract from, multiply or devide a Gap to scale it, e.g. Gap() * 2.

There is also a package named "Gap", which works in a similar way, but has a few more features, which I personally don't need.

ThemedText #

Avoid accessing ThemeData manually to set a themed textStyle. Use a ThemedText widget instead:

ThemedText.headlineMedium('Some headline');

AsyncBuilder #

Using Flutter's FutureBuilder requires a lot of imperative boilerplate.
You need to explicitly catch loading, error and no-data states while also keeping the Future in state.
If you do this: FutureBuilder(future: load(), builder: ...);, then FutureBuilder will call load() whenever your widget rebuilds.

As an alternative, AsyncBuilder offers a declarative API:

AsyncBuilder(
  createFuture: (context) => Future.delayed(
    const Duration(seconds: 1),
    () => 'some data',
  ),
  builder: (context, data) => Text(data),
);

AsyncBuilder only reloads when its key changes. You can also customize initialData and change the look of loading, no-data and error states, which each have sensible defaults.

Use AsyncBuilder.asset to avoid explicitly getting the DefaultAssetBundle from BuildContext:

AsyncBuilder.asset(
  (assetBundle) => assetBundle.loadString('assets/file.txt'),
  builder: (context, data) => Text(data),
);

Spinner #

Spinner is essentially a slightly improved CircularProgressIndicator.
It is always centered, can be given a fixed size, its strokeWidth is a bit more narrow and it all can be themed using SpinnerThemeData.
It is also the default loading indicator used by AsyncBuilder.

Flutter comes with some clickable and tappable widgets, but none that look like a regular HTML <a> tag.
The Link widget is just that. It performs an action when tapped and makes its child: Text look like an HTML link with an underline and that classic blue color. This style can be customized through constructor parameters or by using the LinkThemeData theme extension.

Link(
  onTap: () {
    // do something
  },
  child: const Text('Click me'),
),

Pagination #

Need improved performance when displaying many elements on screen at once? Try Pagination:

Pagination(
  maxPageSize: 20,
  // getPage returns a `Paginated` instance with `totalItemCount` and generic `items`
  getPage: (int pageIndex) => ...
  builder: (context, items) => ListView(
    children: [
      for (final item in items)
        ListTile(
          title: Text(item),
        ),
    ],
  ),
),

Pagination calls getPage, handles the Future and displays numbered controls below the return value of builder, which can be customized with PaginationThemeData. If needed, disable controls with showControls: false and take external control using a PaginationController.

3
likes
0
points
37
downloads

Publisher

unverified uploader

Weekly Downloads

Extensions and widgets that are missing in Flutter's SDK.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter

More

Packages that depend on micha_core