In JavaScript, messing with the native objects' prototypes is a bad idea. It can cause problems with third-party libraries that rely on it. But Dart have extension just like how C# does. It allows you to add new methods to existing classes without creating new derivatives nor modifying the original classes (like changing the prototype in JS). This is totally fine in Dart and C# and not a bad practice at all. I've made some Dart extensions snippets for myself and I want to share it here.
extension DoubleExtension on double {
double clampLower(double value) => max(this, value);
double clampUpper(double value) => min(this, value);
double normalize(double lowerBound, double upperBound) =>
(this - lowerBound) / (upperBound - lowerBound);
double lerp(double lowerBound, double upperBound) =>
this * (upperBound - lowerBound) + lowerBound;
double complementary() => 1 - this;
}
extension IntExtension on int {
int clampLower(int value) => max(this, value);
int clampUpper(int value) => min(this, value);
}
extension GlobalKeyExtension on GlobalKey {
RenderBox? findRenderBox() {
return currentContext?.findRenderObject() as RenderBox;
}
Size? calculateWidgetSize() {
return findRenderBox()?.size;
}
Offset? calculateWidgetOffset([RenderObject? ancestor]) {
final vec = findRenderBox()?.getTransformTo(ancestor).getTranslation();
if (vec == null) return null;
return Offset(vec.x, vec.y);
}
}
extension OrientationExtension on Orientation {
bool get isPortrait => this == Orientation.portrait;
bool get isLandscape => this == Orientation.landscape;
Orientation get opposite =>
isPortrait ? Orientation.landscape : Orientation.portrait;
}
extension BrightnessExtension on Brightness {
bool get isLight => this == Brightness.light;
bool get isDark => this == Brightness.dark;
Brightness get opposite => isLight ? Brightness.dark : Brightness.light;
}
extension TargetPlatformExtension on TargetPlatform {
bool get isAndroid => this == TargetPlatform.android;
bool get isIOS => this == TargetPlatform.iOS;
bool get isMobile => isAndroid || isIOS;
bool get isDesktop => !isMobile;
}
extension UiImage on ui.Image {
Future<img.Image?> toEncodableImage() async {
final byteData = await toByteData();
if (byteData == null) return null;
return img.Image.fromBytes(
width: width,
height: height,
order: img.ChannelOrder.rgba,
bytes: byteData.buffer,
);
}
}
extension ImgImage on img.Image {
Future<ui.Image> toUiImage() async {
final codec = await ui.instantiateImageCodec(img.encodePng(this));
final info = await codec.getNextFrame();
return info.image;
}
}
extension TimeOfDayExtension on TimeOfDay {
int get _comparator => hour * 60 + minute;
bool isBefore(TimeOfDay compareTo) {
return _comparator < compareTo._comparator;
}
bool isAfter(TimeOfDay compareTo) {
return _comparator > compareTo._comparator;
}
}