Skip to content

Instantly share code, notes, and snippets.

@dickermoshe
Created November 7, 2025 13:57
Show Gist options
  • Select an option

  • Save dickermoshe/465429e2c4f085756d7a9379d9e839f8 to your computer and use it in GitHub Desktop.

Select an option

Save dickermoshe/465429e2c4f085756d7a9379d9e839f8 to your computer and use it in GitHub Desktop.
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:signals/signals_flutter.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends HookWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
final counter = useMemoized(() => signal(0));
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: CoolWidget([
() => counter.value,
ElevatedButton(
child: Text("Add"),
onPressed: () {
counter.value = counter.value + 1;
},
),
]),
),
),
);
}
}
class CoolWidget extends StatelessWidget {
const CoolWidget(
this.child, {
super.key,
this.errorBuilder,
this.loadingBuilder,
});
final Object? child;
/// Custom widget builder for error states (Future/Stream errors)
final Widget Function(
BuildContext context,
Object error,
StackTrace stackTrace,
)?
errorBuilder;
/// Custom widget builder for loading states (Future/Stream loading)
final Widget Function(BuildContext context)? loadingBuilder;
@override
Widget build(BuildContext context) {
return _build(
context: context,
child: child,
errorBuilder: errorBuilder,
loadingBuilder: loadingBuilder,
);
}
}
abstract class Cool extends StatelessWidget {
const Cool({super.key, this.errorBuilder, this.loadingBuilder});
/// Custom widget builder for error states (Future/Stream errors)
final Widget Function(
BuildContext context,
Object error,
StackTrace stackTrace,
)?
errorBuilder;
/// Custom widget builder for loading states (Future/Stream loading)
final Widget Function(BuildContext context)? loadingBuilder;
@override
Widget build(BuildContext context) => _build(
context: context,
child: make(context: context),
errorBuilder: errorBuilder,
loadingBuilder: loadingBuilder,
);
// Must return:
// - Widget
// - String
// - int
// - double
// - bool
// - null
// - List<Object?>
// - Future<T>
// - Stream<T>
// - Widget Function(BuildContext context)
// - Object Function(BuildContext context)
// - Object Function()
Object? make({required BuildContext context});
}
class CoolFlexWidget extends StatelessWidget {
const CoolFlexWidget(
this.children, {
super.key,
this.errorBuilder,
this.loadingBuilder,
this.direction = Axis.vertical,
this.mainAxisAlignment = MainAxisAlignment.start,
this.crossAxisAlignment = CrossAxisAlignment.center,
this.mainAxisSize = MainAxisSize.min,
});
/// List of children to render, each can be any type supported by Cool
final List<Object?> children;
/// Custom widget builder for error states (Future/Stream errors)
final Widget Function(
BuildContext context,
Object error,
StackTrace stackTrace,
)?
errorBuilder;
/// Custom widget builder for loading states (Future/Stream loading)
final Widget Function(BuildContext context)? loadingBuilder;
/// The direction to use as the main axis
final Axis direction;
/// How the children should be placed along the main axis
final MainAxisAlignment mainAxisAlignment;
/// How the children should be placed along the cross axis
final CrossAxisAlignment crossAxisAlignment;
/// How much space should be occupied in the main axis
final MainAxisSize mainAxisSize;
@override
Widget build(BuildContext context) {
return Flex(
direction: direction,
mainAxisAlignment: mainAxisAlignment,
crossAxisAlignment: crossAxisAlignment,
mainAxisSize: mainAxisSize,
children: children
.map(
(child) => _build(
context: context,
child: child,
errorBuilder: errorBuilder,
loadingBuilder: loadingBuilder,
),
)
.toList(),
);
}
}
Widget _build({
required BuildContext context,
required Object? child,
Widget Function(BuildContext context, Object error, StackTrace stackTrace)?
errorBuilder,
Widget Function(BuildContext context)? loadingBuilder,
}) {
if (child == null) {
return const SizedBox.shrink();
}
switch (child) {
case Widget widget:
return widget;
case String string:
return Text(string);
case int number:
return Text(number.toString());
case double number:
return Text(number.toString());
case bool boolean:
return Text(boolean.toString());
case List<Object?> list:
return CoolFlexWidget(
list,
errorBuilder: errorBuilder,
loadingBuilder: loadingBuilder,
);
case Future future:
return FutureBuilder(
future: future,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return loadingBuilder?.call(context) ??
const CircularProgressIndicator();
}
if (snapshot.hasError) {
return errorBuilder?.call(
context,
snapshot.error!,
snapshot.stackTrace!,
) ??
Text('Error: ${snapshot.error}');
}
return _build(
context: context,
child: snapshot.data,
errorBuilder: errorBuilder,
loadingBuilder: loadingBuilder,
);
},
);
case Stream stream:
return StreamBuilder(
stream: stream,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return loadingBuilder?.call(context) ??
const CircularProgressIndicator();
}
if (snapshot.hasError) {
return errorBuilder?.call(
context,
snapshot.error!,
snapshot.stackTrace!,
) ??
Text('Error: ${snapshot.error}');
}
return _build(
context: context,
child: snapshot.data,
errorBuilder: errorBuilder,
loadingBuilder: loadingBuilder,
);
},
);
case Widget Function(BuildContext context) builder:
return Watch.builder(
builder: (context) {
final child = builder(context);
return child;
},
);
case Object Function(BuildContext context) builder:
return Watch.builder(
builder: (context) {
final child = builder(context);
return _build(
context: context,
child: child,
errorBuilder: errorBuilder,
loadingBuilder: loadingBuilder,
);
},
);
case Object Function() builder:
return Watch.builder(
builder: (context) {
final child = builder();
return _build(
context: context,
child: child,
errorBuilder: errorBuilder,
loadingBuilder: loadingBuilder,
);
},
);
default:
throw UnimplementedError('Unsupported child type: $child');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment