Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/JonasWanke/black_hole_flutter

πŸ›  A package absorbing all Flutter utility functions, including extension functions and commonly used widgets
https://github.com/JonasWanke/black_hole_flutter

dart extension-functions flutter hacktoberfest material-design package utility widgets

Last synced: 2 days ago
JSON representation

πŸ›  A package absorbing all Flutter utility functions, including extension functions and commonly used widgets

Awesome Lists containing this project

README

        

πŸ›  A package absorbing all Flutter utility functions, including extension functions and commonly used widgets.

- [πŸ“„ Bottom Sheet](#-bottom-sheet)
- [πŸ— BuildContext](#-buildcontext)
- [🎨 Colors](#-colors)
- [🌈 Material Design colors](#-material-design-colors)
- [🧭 Navigation](#-navigation)
- [πŸ“± Widgets](#-widgets)
- [πŸ”³ Buttons](#-buttons)
- [πŸ₯™ FillOrWrap](#-fillorwrap)
- [🎯 LeftCenterRight](#-leftcenterright)
- [πŸ–Ό RenderObject](#-renderobject)
- [↕ Size](#-size)

## πŸ“„ Bottom Sheet

Show modal bottom sheets using: [`context.showModalBottomSheet()`].

FancyBottomSheet demo

Also, this package adds a custom [`FancyBottomSheet`] with a drag indicator at the top. You can create one using [`context.showFancyModalBottomSheet()`].

[`context.showModalBottomSheet()`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/BottomSheetContext/showModalBottomSheet.html
[`context.showFancyModalBottomSheet()`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/BottomSheetContext/showFancyModalBottomSheet.html
[`FancyBottomSheet`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/BottomSheetContext.html

## πŸ— BuildContext

In Flutter, you often see the pattern `.of(context)` (e.g., [`Theme.of(context)`][`Theme.of`]). This package adds extension getters on [`BuildContext`] for those classes so you can just say:

| Extension | Shortcut for |
| --------------------------------- | ------------------------------------ |
| [`context.defaultTextStyle`] | `DefaultTextStyle.of(context)` |
| [`context.directionality`] | `Directionality.of(context)` |
| [`context.form`] | `Form.of(context)` |
| [`context.locale`] | `Localizations.localeOf(context)` |
| [`context.materialLocalizations`] | `MaterialLocalizations.of(context)` |
| [`context.mediaQuery`] | `MediaQuery.of(context)` |
| [`context.overlay`] | `Overlay.of(context)` |
| [`context.pageStorage`] | `PageStorage.of(context)` |
| [`context.scaffold`] | `Scaffold.of(context)` |
| [`context.scaffoldOrNull`] | `Scaffold.of(context, nullOk: true)` |
| [`context.textTheme`] | `Theme.of(context).textTheme` |
| [`context.theme`] | `Theme.of(context)` |

[`context.defaultTextStyle`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyContext/defaultTextStyle.html
[`context.directionality`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyContext/directionality.html
[`context.form`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyContext/form.html
[`context.locale`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyContext/locale.html
[`context.materialLocalizations`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyContext/materialLocalizations.html
[`context.mediaQuery`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyContext/mediaQuery.html
[`context.overlay`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyContext/overlay.html
[`context.pageStorage`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyContext/pageStorage.html
[`context.scaffold`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyContext/scaffold.html
[`context.scaffoldOrNull`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyContext/scaffoldOrNull.html
[`context.textTheme`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyContext/textTheme.html
[`context.theme`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyContext/theme.html

## 🎨 Colors

Handy extensions on [`Brightness`]:

| Extension | Explanation |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| [`brightness.isDark`] | ≙ `brightness == Brightness.dark` |
| [`brightness.isLight`] | ≙ `brightness == Brightness.light` |
| [`brightness.opposite`] | opposite Brightness |
| [`brightness.color`] | [`Color`] representing this brightness, i.e.:
Β· `Colors.white` for `Brightness.light`
Β· `Colors.black` for `Brightness.dark` |
| [`brightness.contrastColor`] | opposite of `brightness.color` (above) |

`isDark`, `isLight`, and `contrastColor` can also be used on [`ThemeData`] directly.

Handy extensions on [`Color`]:

| Extension | Explanation |
| ----------------------------------------------- | --------------------------------------------------------------- |
| [`color.estimatedBrightness`] | estimated [`Brightness`] based on `color`'s luminance |
| [`color.isOpaque`] | if opacity is `1.0` |
| [`color.alphaBlendOn(Color background)`] | resulting [`Color`] when drawing `color` on top of `background` |
| [`color.withAdditionalOpacity(double opacity)`] | applies `opacity` by multiplying it to the existing opacity |
| [`color.withAdditionalAlpha(int alpha)`] | like above, but with an integer alpha |
| [`color.hsl`] | ≙ `HSLColor.fromColor(color)` |
| [`color.hsv`] | ≙ `HSVColor.fromColor(color)` |

And if you can't decide on a color, just use [`random.nextColor()`], [`random.nextColorHsl()`] or [`random.nextColorHsv()`]!

Convert between alpha and opacity with `int.alphaToOpacity` and `double.opacityToAlpha`.

[`brightness.isDark`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyBrightness/isDark.html
[`brightness.isLight`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyBrightness/isLight.html
[`brightness.opposite`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyBrightness/opposite.html
[`brightness.color`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyBrightness/color.html
[`brightness.contrastColor`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyBrightness/contrastColor.html
[`color.alphaBlendOn(Color background)`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyColor/alphaBlendOn.html
[`color.estimatedBrightness`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyColor/estimatedBrightness.html
[`color.isOpaque`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyColor/isOpaque.html
[`color.hsl`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyColor/hsl.html
[`color.hsv`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyColor/hsv.html
[`color.withAdditionalOpacity(double opacity)`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyColor/withAdditionalOpacity.html
[`color.withAdditionalAlpha(int alpha)`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyColor/withAdditionalAlpha.html
[`random.nextColor()`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/RandomColor/nextColor.html
[`random.nextColorHsl()`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/RandomColor/nextColorHsl.html
[`random.nextColorHsv()`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/RandomColor/nextColorHsv.html

### 🌈 Material Design colors

[Material Design](https://material.io/design/color/text-legibility.html) specifies different opacities of white and black colors to use for text of different emphases on colored backgrounds. You can now use the [`highEmphasisOnColor`][`MaterialColors.highEmphasisOnColor`], [`mediumEmphasisOnColor`][`MaterialColors.mediumEmphasisOnColor`] and [`disabledOnColor`][`MaterialColors.disabledOnColor`] extension getters on [`Color`] to make your text legible!

There are also getters on [`ThemeData`] for contrast colors on the primary, accent, background, and error colors.

[`MaterialColors.disabledOnColor`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/MaterialColors/disabledOnColor.html
[`MaterialColors.highEmphasisOnColor`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/MaterialColors/highEmphasisOnColor.html
[`MaterialColors.mediumEmphasisOnColor`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/MaterialColors/mediumEmphasisOnColor.html

## 🧭 Navigation

Access your navigation-related information via extension methods:

| Extension | Shortcut for |
| ------------------------- | ----------------------------------------- |
| [`context.navigator`] | `Navigator.of(context)` |
| [`context.rootNavigator`] | `Navigator.of(this, rootNavigator: true)` |
| [`context.modalRoute`] | `ModalRoute.of(context)` |

Push a new route and pop all previous routes (e.g., when signing out the user):

```dart
navigator.pushAndRemoveAll(/* new route */);
// Or using a named route:
navigator.pushNamedAndRemoveAll(/* route name */);
```

Log navigation events to the console:

```dart
MaterialApp(
navigatorObservers: [LoggingNavigatorObserver()],
// ...
)
// Prints:
// Navigator: didPush /dashboard β†’ /articles/12345
// Navigator: didPop /dashboard ← /articles/12345
```

> **Note:** This uses the `name` of routes, so it only works with [named routes](https://flutter.dev/docs/cookbook/navigation/named-routes). If you want to handle all your routing declaratively with proper deep links, check out my package [🧭 flutter_deep_linking] :)

[`context.modalRoute`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/NavigationContext/modalRoute.html
[`context.navigator`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/NavigationContext/navigator.html
[`context.rootNavigator`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/NavigationContext/rootNavigator.html

## πŸ“± Widgets

### πŸ”³ Buttons

Did you ever want to show a [progress indicator][`ProgressIndicator`] inside a button? Or were annoyed to conditionally set a [Button][`MaterialButton`]'s [`onPressed`][`MaterialButton.onPressed`] to disable it? Fear no more — black_hole_flutter has got you covered!

![Button demo](https://github.com/JonasWanke/black_hole_flutter/raw/main/doc/widgets-buttons.gif?raw=true)

In [`FancyFab`] (a [`FloatingActionButton`]), [`FancyTextButton`], [`FancyOutlinedButton`], and [`FancyElevatedButton`], we introduce some new parameters:

- [`isLoading`][`FancyFab.isLoading`]: Setting this to `true` shows a [`CircularProgressIndicator`] and disables this button. You can optionally specify a [`loadingChild`][`FancyTextButton.loadingChild`] ([`loadingLabel`][`FancyFab.loadingLabel`] on [`FancyFab`]) to show next to the progress indicator.
- `isEnabled`: Settings this to `false` disables this button, even if [`onPressed`][`FancyFab.onPressed`] is set.

[`FancyFab`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyFab-class.html
[`FancyFab.isLoading`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyFab/isLoading.html
[`FancyFab.loadingLabel`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyFab/loadingLabel.html
[`FancyFab.onPressed`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyFab/onPressed.html
[`FancyTextButton`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyTextButton-class.html
[`FancyTextButton.loadingChild`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyTextButton/loadingChild.html
[`FancyOutlinedButton`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyOutlinedButton-class.html
[`FancyElevatedButton`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancyElevatedButton-class.html

### πŸ₯™ FillOrWrap

FillOrWrap demo

A layout with two different behaviors:

- By default, all children are positioned **next to each other with equal widths**. This is comparable to a [`Row`] with all children wrapped in [`Expanded`].
- If the children are too wide to fit in a single line, or one child would become smaller than its reported minimum width, the children get positioned **below each other** ("wrapped"). This is similar to a [`Column`] with [`MainAxisSize.min`].

### 🎯 LeftCenterRight

A layout taking optional `left`, `center`, and `right` children.
It will try to keep `center` in the center of itself, even if only one of `left` and `right` is set or they have different widths.

## πŸ–Ό RenderObject

When writing a custom layout, you might find this extension on [`ContainerRenderObjectMixin`] useful:

| Extension | Explanation |
| --------------------------------------- | -------------------------------------------------------- |
| [`containerRenderObjectMixin.children`] | Returns all children using `firstChild` and `childAfter` |

[`containerRenderObjectMixin.children`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/ContainerRenderObjectMixinBlackHole/children.html

## ↕ Size

| Extension | Explanation |
| ------------------------------------ | -------------------------------------------------------- |
| [`size.diagonal`] | length of the diagonal of a rectangle with this [`Size`] |
| [`size.squaredDiagonal`] | ≙ `size.diagonal * size.diagonal` |
| [`size.coerceAtLeast(Size minimum)`] | Ensures `size` is not smaller than `minimum` in any axis |
| [`size.coerceAtMost(Size maximum)`] | Ensures `size` is not larger than `minimum` in any axis |

[`size.diagonal`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancySize/diagonal.html
[`size.squaredDiagonal`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancySize/squaredDiagonal.html
[`size.coerceAtLeast(Size minimum)`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancySize/coerceAtLeast.html
[`size.coerceAtMost(Size maximum)`]: https://pub.dev/documentation/black_hole_flutter/latest/black_hole_flutter/FancySize/coerceAtMost.html
[🧭 flutter_deep_linking]: https://pub.dev/packages/flutter_deep_linking

[`BuildContext`]: https://api.flutter.dev/flutter/widgets/BuildContext-class.html
[`Brightness`]: https://api.flutter.dev/flutter/dart-ui/Brightness-class.html
[`CircularProgressIndicator`]: https://api.flutter.dev/flutter/material/CircularProgressIndicator-class.html
[`Color`]: https://api.flutter.dev/flutter/dart-ui/Color-class.html
[`Column`]: https://api.flutter.dev/flutter/widgets/Column-class.html
[`ContainerRenderObjectMixin`]: https://api.flutter.dev/flutter/rendering/ContainerRenderObjectMixin-mixin.html
[`Expanded`]: https://api.flutter.dev/flutter/widgets/Expanded-class.html
[`FloatingActionButton`]: https://api.flutter.dev/flutter/material/FloatingActionButton-class.html
[`MainAxisSize.min`]: https://api.flutter.dev/flutter/rendering/MainAxisSize-class.html#min
[`MaterialButton`]: https://api.flutter.dev/flutter/material/MaterialButton-class.html
[`MaterialButton.onPressed`]: https://api.flutter.dev/flutter/material/MaterialButton/onPressed.html
[`ProgressIndicator`]: https://api.flutter.dev/flutter/material/ProgressIndicator-class.html
[`Row`]: https://api.flutter.dev/flutter/widgets/Row-class.html
[`Size`]: https://api.flutter.dev/flutter/dart-ui/Size-class.html
[`Theme.of`]: https://api.flutter.dev/flutter/material/Theme/of.html
[`ThemeData`]: https://api.flutter.dev/flutter/material/ThemeData-class.html