proviso 2.0.0
proviso: ^2.0.0 copied to clipboard
Complete set of tools for widgets conditional rendering and wrapping. Conditional widgets and builders.
proviso #
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!