proviso 2.0.0 copy "proviso: ^2.0.0" to clipboard
proviso: ^2.0.0 copied to clipboard

Complete set of tools for widgets conditional rendering and wrapping. Conditional widgets and builders.

proviso #

stability-stable License

A complete set of tools for conditional rendering (if-else and switch conditions), subtree wrapping with a parent widget, async state handling (Future/Stream), platform-aware rendering, reactive ValueNotifier conditions, animated transitions, and some handy shortcuts (like DebugWidget, WebOnlyWidget, SafeBuilder, and many more). 👍

Install #

In flutter project add the dependency:

dependencies:
  ...
  proviso: ^2.0.0

Why #

To make a more readable and simpler conditional statement code.

Widgets #

ConditionWidget #

Render a widget or fallback based on a condition:

Row(
  children: [
    ConditionWidget(
      condition: starred,
      widget: Icon(Icons.favorite),
      fallback: fallbackWidget,
    ),
    ConditionWidget(
      condition: archived,
      widget: Icon(Icons.archive),
    ),
  ],
)

ConditionBuilder #

Lazy builder variant — widgets are only built when needed:

ConditionBuilder(
  condition: (_) => someCondition,
  trueBuilder: (_) => trueWidget,
  fallbackBuilder: (_) => fallbackWidget,
);

Conditional & ConditionalBuilder (static methods) #

Useful inside children lists without wrapping in a widget:

Column(
  children: [
    Conditional.widget(
      context: context,
      condition: isActive,
      widget: Text('Active'),
      fallback: Text('Inactive'),
    ),
    ...Conditional.widgets(
      context: context,
      condition: hasItems,
      widgets: [Item1(), Item2()],
    ),
  ],
)

Generic builder:

final String label = ConditionalBuilder.generic<String>(
  context: context,
  condition: (_) => isSelected,
  trueBuilder: (_) => 'Selected',
  fallbackBuilder: (_) => 'Not selected',
);

SwitchCase & SwitchCaseBuilder #

Switch-case rendering with maps:

SwitchCaseBuilder.widget<String>(
  context: context,
  condition: (_) => status,
  caseBuilders: {
    'active': (_) => ActiveWidget(),
    'inactive': (_) => InactiveWidget(),
  },
  fallbackBuilder: (_) => UnknownWidget(),
);

Widget variant:

SwitchCase.widget<ThemeMode>(
  context: context,
  condition: ThemeMode.dark,
  caseWidgets: {
    ThemeMode.dark: DarkIcon(),
    ThemeMode.light: LightIcon(),
  },
);

ConditionalWrap #

Conditionally wrap a child in a parent widget:

ConditionalWrap(
  shouldWrap: needsPadding,
  child: MyWidget(),
  parentBuilder: (child) => Padding(
    padding: EdgeInsets.all(16),
    child: child,
  ),
)

With an else branch:

ConditionalWrap(
  shouldWrap: isSelected,
  child: Text('Hello'),
  parentBuilder: (child) => Container(
    color: Colors.blue,
    child: child,
  ),
  elseParentBuilder: (child) => Container(
    color: Colors.grey,
    child: child,
  ),
)

SafeBuilder #

Try/catch for widget building:

SafeBuilder(
  widgetBuilder: (_) => riskyWidget,
  fallbackBuilder: (error, stackTrace, _) => ErrorWidget(error),
)

PlatformWidget #

Render different widgets per platform:

PlatformWidget(
  android: (_) => MaterialWidget(),
  ios: (_) => CupertinoWidget(),
  web: (_) => WebWidget(),
  fallback: (_) => DefaultWidget(),
)

MediaQueryCondition #

Conditional rendering based on screen size:

MediaQueryCondition(
  condition: (_, mq) => mq.size.width > 600,
  builder: (_) => WideLayout(),
  fallbackBuilder: (_) => NarrowLayout(),
)

OrientationCondition #

Landscape vs portrait:

OrientationCondition(
  landscape: (_) => LandscapeLayout(),
  portrait: (_) => PortraitLayout(),
)

AsyncConditional #

Handle Future states (loading/data/error):

AsyncConditional<User>(
  future: fetchUser(),
  loading: (_) => CircularProgressIndicator(),
  data: (_, user) => Text(user.name),
  error: (_, error, __) => Text('Error: $error'),
)

StreamConditional #

Handle Stream states:

StreamConditional<int>(
  stream: counterStream,
  data: (_, count) => Text('$count'),
  loading: (_) => Text('Waiting...'),
)

AnimatedConditional #

Animated transition between conditions:

AnimatedConditional(
  condition: isVisible,
  trueWidget: DetailView(),
  falseWidget: SummaryView(),
  duration: Duration(milliseconds: 300),
)

With custom transition:

AnimatedConditional(
  condition: isVisible,
  trueWidget: DetailView(),
  falseWidget: SummaryView(),
  transitionBuilder: (child, animation) => ScaleTransition(
    scale: animation,
    child: child,
  ),
)

ReactiveConditional #

Rebuilds when a ValueNotifier changes:

final isActive = ValueNotifier<bool>(false);

ReactiveConditional<bool>(
  notifier: isActive,
  condition: (value) => value,
  trueBuilder: (_) => ActiveWidget(),
  fallbackBuilder: (_) => InactiveWidget(),
)

IfNotEmpty #

Conditional rendering based on collection emptiness:

IfNotEmpty<User>(
  items: users,
  builder: (_, users) => UserList(users: users),
  fallbackBuilder: (_) => EmptyState(),
)

Map variant:

IfNotEmptyMap<String, Widget>(
  items: sections,
  builder: (_, sections) => SectionList(sections: sections),
)

Shortcuts #

DebugModeWidget(widget: Text('Only visible in debug'))
ReleaseModeWidget(widget: Text('Only visible in release'))
WebOnlyWidget(widget: Text('Only visible on web'))

Contributions #

Feel free to report bugs, request new features or to contribute to this project!

5
likes
150
points
177
downloads

Documentation

API reference

Publisher

verified publishermos-dev.com

Weekly Downloads

Complete set of tools for widgets conditional rendering and wrapping. Conditional widgets and builders.

Repository (GitHub)
View/report issues

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on proviso