From 1dc1f0478648c54f911b3fb3d5f46e166f8e4021 Mon Sep 17 00:00:00 2001 From: Jonas Wanke Date: Thu, 25 Feb 2021 10:14:17 +0100 Subject: [PATCH] feat: support null-safety Closes: #1 --- example/lib/buttons.dart | 78 +++--- example/lib/main.dart | 22 +- example/pubspec.lock | 78 +++--- example/pubspec.yaml | 6 +- lib/src/bottom_sheet.dart | 28 +- lib/src/color.dart | 37 ++- lib/src/context.dart | 10 +- lib/src/navigation.dart | 26 +- lib/src/size.dart | 22 +- lib/src/widgets/buttons.dart | 323 ++++++++++-------------- lib/src/widgets/chip_group.dart | 13 +- lib/src/widgets/fill_or_wrap.dart | 44 ++-- lib/src/widgets/separated_buttons.dart | 15 +- lib/src/widgets/title_and_subtitle.dart | 15 +- pubspec.yaml | 13 +- 15 files changed, 312 insertions(+), 418 deletions(-) diff --git a/example/lib/buttons.dart b/example/lib/buttons.dart index ef39712..0510f29 100644 --- a/example/lib/buttons.dart +++ b/example/lib/buttons.dart @@ -26,15 +26,15 @@ class ButtonsExample extends StatelessWidget { Text('isLoading: true'), ]), _buildSpacerRow(), - _buildFancyFlatButtonRow(), + _buildFancyTextButtonRow(), _buildSpacerRow(), _buildFancyIconFlatButtonRow(), _buildSpacerRow(), - _buildFancyOutlineButtonRow(), + _buildFancyOutlinedButtonRow(), _buildSpacerRow(), _buildFancyIconOutlineButtonRow(), _buildSpacerRow(), - _buildFancyRaisedButtonRow(), + _buildFancyElevatedButtonRow(), _buildSpacerRow(), _buildFancyIconRaisedButtonRow(), _buildSpacerRow(), @@ -49,56 +49,56 @@ class ButtonsExample extends StatelessWidget { ); } - TableRow _buildFancyFlatButtonRow() => _buildRow('FancyFlatButton', [ - FancyFlatButton( + TableRow _buildFancyTextButtonRow() => _buildRow('FancyTextButton', [ + FancyTextButton( onPressed: () {}, child: Text('child'), ), - FancyFlatButton( + FancyTextButton( onPressed: null, child: Text('child'), ), - FancyFlatButton( + FancyTextButton( isEnabled: false, onPressed: () {}, child: Text('child'), ), - FancyFlatButton( + FancyTextButton( onPressed: () {}, isLoading: true, child: Text('child'), ), - FancyFlatButton( + FancyTextButton( onPressed: () {}, isLoading: true, loadingChild: Text('loadingChild'), child: Text('child'), ), ]); - TableRow _buildFancyIconFlatButtonRow() => _buildRow('FancyFlatButton.icon', [ - FancyFlatButton.icon( + TableRow _buildFancyIconFlatButtonRow() => _buildRow('FancyTextButton.icon', [ + FancyTextButton.icon( onPressed: () {}, label: Text('label'), icon: Icon(Icons.favorite), ), - FancyFlatButton.icon( + FancyTextButton.icon( onPressed: null, label: Text('label'), icon: Icon(Icons.favorite), ), - FancyFlatButton.icon( + FancyTextButton.icon( isEnabled: false, onPressed: () {}, label: Text('label'), icon: Icon(Icons.favorite), ), - FancyFlatButton.icon( + FancyTextButton.icon( onPressed: () {}, isLoading: true, label: Text('label'), icon: Icon(Icons.favorite), ), - FancyFlatButton.icon( + FancyTextButton.icon( onPressed: () {}, isLoading: true, loadingLabel: Text('loadingLabel'), @@ -107,26 +107,26 @@ class ButtonsExample extends StatelessWidget { ), ]); - TableRow _buildFancyOutlineButtonRow() => _buildRow('FancyOutlineButton', [ - FancyOutlineButton( + TableRow _buildFancyOutlinedButtonRow() => _buildRow('FancyOutlinedButton', [ + FancyOutlinedButton( onPressed: () {}, child: Text('child'), ), - FancyOutlineButton( + FancyOutlinedButton( onPressed: null, child: Text('child'), ), - FancyOutlineButton( + FancyOutlinedButton( isEnabled: false, onPressed: () {}, child: Text('child'), ), - FancyOutlineButton( + FancyOutlinedButton( onPressed: () {}, isLoading: true, child: Text('child'), ), - FancyOutlineButton( + FancyOutlinedButton( onPressed: () {}, isLoading: true, loadingChild: Text('loadingChild'), @@ -134,30 +134,30 @@ class ButtonsExample extends StatelessWidget { ), ]); TableRow _buildFancyIconOutlineButtonRow() => - _buildRow('FancyOutlineButton.icon', [ - FancyOutlineButton.icon( + _buildRow('FancyOutlinedButton.icon', [ + FancyOutlinedButton.icon( onPressed: () {}, label: Text('label'), icon: Icon(Icons.favorite), ), - FancyOutlineButton.icon( + FancyOutlinedButton.icon( onPressed: null, label: Text('label'), icon: Icon(Icons.favorite), ), - FancyOutlineButton.icon( + FancyOutlinedButton.icon( isEnabled: false, onPressed: () {}, label: Text('label'), icon: Icon(Icons.favorite), ), - FancyOutlineButton.icon( + FancyOutlinedButton.icon( onPressed: () {}, isLoading: true, label: Text('label'), icon: Icon(Icons.favorite), ), - FancyOutlineButton.icon( + FancyOutlinedButton.icon( onPressed: () {}, isLoading: true, loadingLabel: Text('loadingLabel'), @@ -166,26 +166,26 @@ class ButtonsExample extends StatelessWidget { ), ]); - TableRow _buildFancyRaisedButtonRow() => _buildRow('FancyRaisedButton', [ - FancyRaisedButton( + TableRow _buildFancyElevatedButtonRow() => _buildRow('FancyElevatedButton', [ + FancyElevatedButton( onPressed: () {}, child: Text('child'), ), - FancyRaisedButton( + FancyElevatedButton( onPressed: null, child: Text('child'), ), - FancyRaisedButton( + FancyElevatedButton( isEnabled: false, onPressed: () {}, child: Text('child'), ), - FancyRaisedButton( + FancyElevatedButton( onPressed: () {}, isLoading: true, child: Text('child'), ), - FancyRaisedButton( + FancyElevatedButton( onPressed: () {}, isLoading: true, loadingChild: Text('loadingChild'), @@ -193,30 +193,30 @@ class ButtonsExample extends StatelessWidget { ), ]); TableRow _buildFancyIconRaisedButtonRow() => - _buildRow('FancyRaisedButton.icon', [ - FancyRaisedButton.icon( + _buildRow('FancyElevatedButton.icon', [ + FancyElevatedButton.icon( onPressed: () {}, label: Text('label'), icon: Icon(Icons.favorite), ), - FancyRaisedButton.icon( + FancyElevatedButton.icon( onPressed: null, label: Text('label'), icon: Icon(Icons.favorite), ), - FancyRaisedButton.icon( + FancyElevatedButton.icon( isEnabled: false, onPressed: () {}, label: Text('label'), icon: Icon(Icons.favorite), ), - FancyRaisedButton.icon( + FancyElevatedButton.icon( onPressed: () {}, isLoading: true, label: Text('label'), icon: Icon(Icons.favorite), ), - FancyRaisedButton.icon( + FancyElevatedButton.icon( onPressed: () {}, isLoading: true, loadingLabel: Text('loadingLabel'), diff --git a/example/lib/main.dart b/example/lib/main.dart index 9b7fb1a..420a7ca 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -30,7 +30,7 @@ class BottomSheetExample extends StatelessWidget { return Section( title: 'FancyBottomSheet', children: [ - FancyRaisedButton( + FancyElevatedButton( onPressed: () { context.showFancyModalBottomSheet( builder: (_) => Padding( @@ -82,9 +82,9 @@ class SeparatedButtonsExample extends StatelessWidget { children: [ SeparatedButtons( children: [ - FlatButton(onPressed: () {}, child: Text('Imprint')), - FlatButton(onPressed: () {}, child: Text('Privacy Policy')), - FlatButton(onPressed: () {}, child: Text('Licenses')), + TextButton(onPressed: () {}, child: Text('Imprint')), + TextButton(onPressed: () {}, child: Text('Privacy Policy')), + TextButton(onPressed: () {}, child: Text('Licenses')), ], ), ], @@ -107,7 +107,7 @@ class FillOrWrapExample extends StatelessWidget { ); } - Widget _buildExample({bool isConstrained}) { + Widget _buildExample({required bool isConstrained}) { return Center( child: Container( constraints: isConstrained ? BoxConstraints(maxWidth: 200) : null, @@ -116,9 +116,9 @@ class FillOrWrapExample extends StatelessWidget { spacing: 8, wrappedSpacing: 8, children: [ - RaisedButton(onPressed: () {}, child: Text('Short')), - RaisedButton(onPressed: () {}, child: Text('Loooooooooong')), - RaisedButton(onPressed: () {}, child: Text('Short')), + TextButton(onPressed: () {}, child: Text('Short')), + TextButton(onPressed: () {}, child: Text('Loooooooooong')), + TextButton(onPressed: () {}, child: Text('Short')), ], ), ), @@ -127,10 +127,8 @@ class FillOrWrapExample extends StatelessWidget { } class Section extends StatelessWidget { - const Section({Key key, @required this.title, @required this.children}) - : assert(title != null), - assert(children != null), - super(key: key); + const Section({Key? key, required this.title, required this.children}) + : super(key: key); final String title; final List children; diff --git a/example/pubspec.lock b/example/pubspec.lock index 49c849a..4cb2a99 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.3" + version: "2.5.0" black_hole_flutter: dependency: "direct main" description: @@ -21,63 +21,42 @@ packages: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.5" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.5" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.4" - dartx: - dependency: transitive - description: - name: dartx - url: "https://pub.dartlang.org" - source: hosted - version: "0.5.0" + version: "1.15.0" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" flutter: dependency: "direct main" description: flutter @@ -94,21 +73,21 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.3" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.6" + version: "1.3.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.3" + version: "1.8.0" sky_engine: dependency: transitive description: flutter @@ -120,63 +99,70 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.4" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.6" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" - term_glyph: + version: "1.1.0" + supercharged: dependency: transitive description: - name: term_glyph + name: supercharged url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" - test_api: + version: "2.0.0-nullsafety.2" + supercharged_dart: dependency: transitive description: - name: test_api + name: supercharged_dart url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.6" - time: + version: "2.0.0-nullsafety.1" + term_glyph: dependency: transitive description: - name: time + name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.19" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.5" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.5" + version: "2.1.0" sdks: dart: ">=2.12.0-0.0 <3.0.0" flutter: ">=1.24.0-7.0.pre" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 170a875..ad0beda 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,10 +1,10 @@ name: black_hole_flutter_example -description: "Example for πŸ›  black_hole_flutter, a package absorbing all Flutter utility functions" +description: 'Example for πŸ›  black_hole_flutter, a package absorbing all Flutter utility functions' version: 0.2.16 -publish_to: "none" +publish_to: 'none' environment: - sdk: ">=2.3.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' dependencies: black_hole_flutter: diff --git a/lib/src/bottom_sheet.dart b/lib/src/bottom_sheet.dart index 7f2c7a8..08cbde7 100644 --- a/lib/src/bottom_sheet.dart +++ b/lib/src/bottom_sheet.dart @@ -4,12 +4,12 @@ import 'context.dart'; extension BottomSheetContext on BuildContext { /// Shortcut for `showModalBottomSheet(context: context, ...)`. - Future showModalBottomSheet({ - @required WidgetBuilder builder, - Color backgroundColor, - double elevation, - ShapeBorder shape, - Clip clipBehavior, + Future showModalBottomSheet({ + required WidgetBuilder builder, + Color? backgroundColor, + double? elevation, + ShapeBorder? shape, + Clip? clipBehavior, bool isScrollControlled = false, bool useRootNavigator = false, bool isDismissible = true, @@ -28,12 +28,12 @@ extension BottomSheetContext on BuildContext { } /// Shortcut for [showModalBottomSheet] with a [FancyBottomSheet] child. - Future showFancyModalBottomSheet({ - @required WidgetBuilder builder, - Color backgroundColor, - double elevation, - ShapeBorder shape, - Clip clipBehavior, + Future showFancyModalBottomSheet({ + required WidgetBuilder builder, + Color? backgroundColor, + double? elevation, + ShapeBorder? shape, + Clip? clipBehavior, bool isScrollControlled = false, bool useRootNavigator = false, bool isDismissible = true, @@ -72,9 +72,7 @@ extension BottomSheetContext on BuildContext { /// ); /// ``` class FancyBottomSheet extends StatelessWidget { - const FancyBottomSheet({Key key, @required this.builder}) - : assert(builder != null), - super(key: key); + const FancyBottomSheet({Key? key, required this.builder}) : super(key: key); final WidgetBuilder builder; diff --git a/lib/src/color.dart b/lib/src/color.dart index ed3a9b6..6828f86 100644 --- a/lib/src/color.dart +++ b/lib/src/color.dart @@ -60,15 +60,12 @@ extension FancyColor on Color { /// Apply [opacity] in addition to the existing opacity by multiplying them. Color withAdditionalOpacity(double opacity) { - assert(opacity != null && opacity >= 0.0 && opacity <= 1.0); + assert(opacity >= 0.0 && opacity <= 1.0); return withOpacity(this.opacity * opacity); } /// Apply [alpha] in addition to the existing alpha by multiplying them. - Color withAdditionalAlpha(int alpha) { - assert(alpha != null); - return withAlpha(this.alpha * alpha); - } + Color withAdditionalAlpha(int alpha) => withAlpha(this.alpha * alpha); /// Shortcut for `HSLColor.fromColor(color)`. HSLColor get hsl => HSLColor.fromColor(this); @@ -97,11 +94,11 @@ extension RandomColor on Random { /// - [red], [green] or [blue] /// - either [alpha] or [opacity] Color nextColor({ - int red, - int green, - int blue, - int alpha, - double opacity, + int? red, + int? green, + int? blue, + int? alpha, + double? opacity, }) { assert( alpha == null || opacity == null, @@ -112,9 +109,7 @@ extension RandomColor on Random { final g = green ?? nextInt(_channelMax); final b = blue ?? nextInt(_channelMax); - if (opacity != null) { - return Color.fromRGBO(r, g, b, opacity); - } + if (opacity != null) return Color.fromRGBO(r, g, b, opacity); return Color.fromARGB(alpha ?? nextInt(_channelMax), r, g, b); } @@ -123,10 +118,10 @@ extension RandomColor on Random { /// /// You can optionally specify some components of the generated [HSLColor]. HSLColor nextColorHsl({ - double hue, - double saturation, - double lightness, - double alpha, + double? hue, + double? saturation, + double? lightness, + double? alpha, }) { final h = hue ?? nextDouble() * 360; final s = saturation ?? nextDouble(); @@ -141,10 +136,10 @@ extension RandomColor on Random { /// /// You can optionally specify some components of the generated [HSVColor]. HSVColor nextColorHsv({ - double hue, - double saturation, - double value, - double alpha, + double? hue, + double? saturation, + double? value, + double? alpha, }) { final h = hue ?? nextDouble() * 360; final s = saturation ?? nextDouble(); diff --git a/lib/src/context.dart b/lib/src/context.dart index 3724fb3..6247eb6 100644 --- a/lib/src/context.dart +++ b/lib/src/context.dart @@ -11,7 +11,7 @@ extension FancyContext on BuildContext { FocusScopeNode get focusScope => FocusScope.of(this); /// Shortcut for `Form.of(context)`. - FormState get form => Form.of(this); + FormState? get form => Form.of(this); /// Shortcut for `Localizations.localeOf(context)`. Locale get locale => Localizations.localeOf(this); @@ -24,22 +24,22 @@ extension FancyContext on BuildContext { MediaQueryData get mediaQuery => MediaQuery.of(this); /// Shortcut for `Overlay.of(context)`. - OverlayState get overlay => Overlay.of(this); + OverlayState? get overlay => Overlay.of(this); /// Shortcut for `PageStorage.of(context)`. - PageStorageBucket get pageStorage => PageStorage.of(this); + PageStorageBucket? get pageStorage => PageStorage.of(this); /// Shortcut for `Scaffold.of(context)`. ScaffoldState get scaffold => Scaffold.of(this); /// Shortcut for `Scaffold.maybeOf(context)`. - ScaffoldState get scaffoldOrNull => Scaffold.maybeOf(this); + ScaffoldState? get scaffoldOrNull => Scaffold.maybeOf(this); /// Shortcut for `ScaffoldMessenger.of(context)`. ScaffoldMessengerState get scaffoldMessenger => ScaffoldMessenger.of(this); /// Shortcut for `ScaffoldMessenger.maybeOf(context)`. - ScaffoldMessengerState get scaffoldMessengerOrNull => + ScaffoldMessengerState? get scaffoldMessengerOrNull => ScaffoldMessenger.maybeOf(this); /// Shortcut for `Theme.of(context)`. diff --git a/lib/src/navigation.dart b/lib/src/navigation.dart index 00786f0..d40fa43 100644 --- a/lib/src/navigation.dart +++ b/lib/src/navigation.dart @@ -2,7 +2,7 @@ import 'package:flutter/widgets.dart'; extension NavigationContext on BuildContext { /// Shortcut for `ModalRoute.of(context)`. - ModalRoute get modalRoute => ModalRoute.of(this); + ModalRoute? getModalRoute() => ModalRoute.of(this); /// Shortcut for `Navigator.of(context)`. NavigatorState get navigator => Navigator.of(this); @@ -14,14 +14,14 @@ extension NavigationContext on BuildContext { extension FancyNavigatorState on NavigatorState { /// Push the given route onto the navigator, and then remove all the previous /// routes. - Future pushAndRemoveAll(Route newRoute) => + Future pushAndRemoveAll(Route newRoute) => pushAndRemoveUntil(newRoute, (_) => false); /// Push the route with the given name onto the navigator, and then remove all /// the previous routes. - Future pushNamedAndRemoveAll( + Future pushNamedAndRemoveAll( String newRouteName, { - Object arguments, + Object? arguments, }) => pushNamedAndRemoveUntil(newRouteName, (_) => false, arguments: arguments); } @@ -31,9 +31,7 @@ typedef MessageLogger = void Function(String message); /// A [NavigatorObserver] that loggs all navigation events to a [MessageLogger] /// (defaults to [print]). class LoggingNavigatorObserver extends NavigatorObserver { - LoggingNavigatorObserver({ - this.logger = defaultLogger, - }) : assert(logger != null); + LoggingNavigatorObserver({this.logger = defaultLogger}); final MessageLogger logger; @@ -41,20 +39,22 @@ class LoggingNavigatorObserver extends NavigatorObserver { static void defaultLogger(String message) => print('Navigator: $message'); @override - void didPush(Route route, Route previousRoute) => logger( + void didPush(Route route, Route? previousRoute) => logger( 'didPush ${routeToString(previousRoute)} β†’ ${routeToString(route)}'); @override - void didPop(Route route, Route previousRoute) => logger( + void didPop(Route route, Route? previousRoute) => logger( 'didPop ${routeToString(previousRoute)} ← ${routeToString(route)}'); @override - void didRemove(Route route, Route previousRoute) => logger( + void didRemove(Route route, Route? previousRoute) => logger( 'didRemove ${routeToString(previousRoute)} β†’ ${routeToString(route)}'); @override - void didReplace({Route newRoute, Route oldRoute}) => logger( - 'didReplace ${routeToString(oldRoute)} β†’ ${routeToString(newRoute)}'); + void didReplace({Route? newRoute, Route? oldRoute}) => + logger( + 'didReplace ${routeToString(oldRoute)} β†’ ${routeToString(newRoute)}'); - String routeToString(Route route) => route?.settings?.name; + String routeToString(Route? route) => + route?.settings.name ?? ''; } diff --git a/lib/src/size.dart b/lib/src/size.dart index b6703f6..2eece09 100644 --- a/lib/src/size.dart +++ b/lib/src/size.dart @@ -1,30 +1,20 @@ -import 'dart:math'; +import 'dart:math' as math; import 'dart:ui'; -import 'package:dartx/dartx.dart'; - extension FancySize on Size { /// The squared length of the diagonal of a rectangle with this [Size]. double get squaredDiagonal => width * width + height * height; /// The length of the diagonal of a rectangle with this [Size]. - double get diagonal => sqrt(squaredDiagonal); + double get diagonal => math.sqrt(squaredDiagonal); /// Ensures that this [Size] is not smaller than the specified [minimum] in /// any axis. - Size coerceAtLeast(Size minimum) { - return Size( - width.coerceAtLeast(minimum.width), - height.coerceAtLeast(minimum.height), - ); - } + Size coerceAtLeast(Size minimum) => + Size(math.max(width, minimum.width), math.max(height, minimum.height)); /// Ensures that this [Size] is not larger than the specified [maximum] in /// any axis. - Size coerceAtMost(Size maximum) { - return Size( - width.coerceAtMost(maximum.width), - height.coerceAtMost(maximum.height), - ); - } + Size coerceAtMost(Size maximum) => + Size(math.min(width, maximum.width), math.min(height, maximum.height)); } diff --git a/lib/src/widgets/buttons.dart b/lib/src/widgets/buttons.dart index a16ac7a..a308a1c 100644 --- a/lib/src/widgets/buttons.dart +++ b/lib/src/widgets/buttons.dart @@ -4,25 +4,23 @@ import 'package:meta/meta.dart'; import '../color_material.dart'; import '../context.dart'; -/// In addition to a normal [FlatButton], this [Widget] natively supports +/// In addition to a normal [TextButton], this [Widget] natively supports /// disabling it and showing a loading state. -class FancyFlatButton extends _FancyButton { - /// Creates a [FlatButton]. +class FancyTextButton extends _FancyButton { + /// Creates a [TextButton]. /// /// {@macro black_hole_flutter.buttons.isEnabled} /// /// [child] and [isLoading] must not be null. - const FancyFlatButton({ - Key key, - bool isEnabled, - @required VoidCallback onPressed, - @required Widget child, + const FancyTextButton({ + Key? key, + bool? isEnabled, + required VoidCallback? onPressed, + required Widget child, bool isLoading = false, - Widget loadingChild, - Widget loadingIndicator, - Color textColor, - Color color, - ShapeBorder shape, + Widget? loadingChild, + Widget? loadingIndicator, + ButtonStyle? style, }) : super( key: key, isEnabled: isEnabled, @@ -31,30 +29,25 @@ class FancyFlatButton extends _FancyButton { isLoading: isLoading, loadingIndicator: loadingIndicator, loadingChild: loadingChild, - textColor: textColor, - color: color, - shape: shape, + style: style, ); - /// Creates a [FlatButton] with a leading icon. + /// Creates a [TextButton] with a leading icon. /// /// {@macro black_hole_flutter.buttons.isEnabled} /// /// [child], [icon] and [isLoading] must not be null. - const FancyFlatButton.icon({ - Key key, - bool isEnabled, - @required VoidCallback onPressed, - @required Widget icon, - @required Widget label, + const FancyTextButton.icon({ + Key? key, + bool? isEnabled, + required VoidCallback? onPressed, + required Widget icon, + required Widget label, bool isLoading = false, - Widget loadingLabel, - Widget loadingIndicator, - Color textColor, - Color color, - ShapeBorder shape, - }) : assert(icon != null), - super( + Widget? loadingLabel, + Widget? loadingIndicator, + ButtonStyle? style, + }) : super( key: key, isEnabled: isEnabled, onPressed: onPressed, @@ -63,56 +56,46 @@ class FancyFlatButton extends _FancyButton { isLoading: isLoading, loadingIndicator: loadingIndicator, loadingChild: loadingLabel, - textColor: textColor, - color: color, - shape: shape, + style: style, ); @override Widget _buildDefault(BuildContext context) { - return FlatButton( + return TextButton( onPressed: actualOnPressed, - textColor: textColor, - color: color, - shape: shape, + style: style, child: child, ); } @override Widget _buildIcon(BuildContext context, Widget icon) { - return FlatButton.icon( + return TextButton.icon( onPressed: actualOnPressed, - textColor: textColor, - color: color, - shape: shape, + style: style, icon: icon, label: actualChild, ); } } -/// In addition to a normal [OutlineButton], this [Widget] natively supports +/// In addition to a normal [OutlinedButton], this [Widget] natively supports /// disabling it and showing a loading state. -class FancyOutlineButton extends _FancyButton { - /// Creates an [OutlineButton]. +class FancyOutlinedButton extends _FancyButton { + /// Creates an [OutlinedButton]. /// /// {@macro black_hole_flutter.buttons.isEnabled} /// /// [child] and [isLoading] must not be null. - const FancyOutlineButton({ - Key key, - bool isEnabled, - @required VoidCallback onPressed, - @required Widget child, + const FancyOutlinedButton({ + Key? key, + bool? isEnabled, + required VoidCallback? onPressed, + required Widget child, bool isLoading = false, - Widget loadingChild, - Widget loadingIndicator, - Color textColor, - Color color, - this.borderSide, - this.highlightedBorderColor, - ShapeBorder shape, + Widget? loadingChild, + Widget? loadingIndicator, + ButtonStyle? style, }) : super( key: key, isEnabled: isEnabled, @@ -121,32 +104,25 @@ class FancyOutlineButton extends _FancyButton { isLoading: isLoading, loadingIndicator: loadingIndicator, loadingChild: loadingChild, - textColor: textColor, - color: color, - shape: shape, + style: style, ); - /// Creates an [OutlineButton] with a leading icon. + /// Creates an [OutlinedButton] with a leading icon. /// /// {@macro black_hole_flutter.buttons.isEnabled} /// /// [child], [icon] and [isLoading] must not be null. - const FancyOutlineButton.icon({ - Key key, - bool isEnabled, - @required VoidCallback onPressed, - @required Widget icon, - @required Widget label, + const FancyOutlinedButton.icon({ + Key? key, + bool? isEnabled, + required VoidCallback? onPressed, + required Widget icon, + required Widget label, bool isLoading = false, - Widget loadingLabel, - Widget loadingIndicator, - Color textColor, - Color color, - this.borderSide, - this.highlightedBorderColor, - ShapeBorder shape, - }) : assert(icon != null), - super( + Widget? loadingLabel, + Widget? loadingIndicator, + ButtonStyle? style, + }) : super( key: key, isEnabled: isEnabled, onPressed: onPressed, @@ -155,61 +131,46 @@ class FancyOutlineButton extends _FancyButton { isLoading: isLoading, loadingIndicator: loadingIndicator, loadingChild: loadingLabel, - textColor: textColor, - color: color, - shape: shape, + style: style, ); - final BorderSide borderSide; - final Color highlightedBorderColor; - @override Widget _buildDefault(BuildContext context) { - return OutlineButton( + return OutlinedButton( onPressed: actualOnPressed, - textColor: textColor, - color: color, - borderSide: borderSide, - highlightedBorderColor: highlightedBorderColor, - shape: shape, + style: style, child: child, ); } @override Widget _buildIcon(BuildContext context, Widget icon) { - return OutlineButton.icon( + return OutlinedButton.icon( onPressed: actualOnPressed, - textColor: textColor, - color: color, - borderSide: borderSide, - highlightedBorderColor: highlightedBorderColor, - shape: shape, + style: style, icon: icon, label: actualChild, ); } } -/// In addition to a normal [RaisedButton], this [Widget] natively supports +/// In addition to a normal [ElevatedButton], this [Widget] natively supports /// disabling it and showing a loading state. -class FancyRaisedButton extends _FancyButton { - /// Creates a [RaisedButton]. +class FancyElevatedButton extends _FancyButton { + /// Creates a [ElevatedButton]. /// /// {@macro black_hole_flutter.buttons.isEnabled} /// /// [child] and [isLoading] must not be null. - const FancyRaisedButton({ - Key key, - bool isEnabled, - @required VoidCallback onPressed, - @required Widget child, + const FancyElevatedButton({ + Key? key, + bool? isEnabled, + required VoidCallback? onPressed, + required Widget child, bool isLoading = false, - Widget loadingChild, - Widget loadingIndicator, - Color textColor, - Color color, - ShapeBorder shape, + Widget? loadingChild, + Widget? loadingIndicator, + ButtonStyle? style, }) : super( key: key, isEnabled: isEnabled, @@ -218,30 +179,25 @@ class FancyRaisedButton extends _FancyButton { isLoading: isLoading, loadingIndicator: loadingIndicator, loadingChild: loadingChild, - textColor: textColor, - color: color, - shape: shape, + style: style, ); - /// Creates a [RaisedButton] with a leading icon. + /// Creates a [ElevatedButton] with a leading icon. /// /// {@macro black_hole_flutter.buttons.isEnabled} /// /// [child], [icon] and [isLoading] must not be null. - const FancyRaisedButton.icon({ - Key key, - bool isEnabled, - @required VoidCallback onPressed, - @required Widget icon, - @required Widget label, + const FancyElevatedButton.icon({ + Key? key, + bool? isEnabled, + required VoidCallback? onPressed, + required Widget icon, + required Widget label, bool isLoading = false, - Widget loadingLabel, - Widget loadingIndicator, - Color textColor, - Color color, - ShapeBorder shape, - }) : assert(icon != null), - super( + Widget? loadingLabel, + Widget? loadingIndicator, + ButtonStyle? style, + }) : super( key: key, isEnabled: isEnabled, onPressed: onPressed, @@ -250,29 +206,23 @@ class FancyRaisedButton extends _FancyButton { isLoading: isLoading, loadingIndicator: loadingIndicator, loadingChild: loadingLabel, - textColor: textColor, - color: color, - shape: shape, + style: style, ); @override Widget _buildDefault(BuildContext context) { - return RaisedButton( + return ElevatedButton( onPressed: actualOnPressed, - textColor: textColor, - color: color, - shape: shape, + style: style, child: child, ); } @override Widget _buildIcon(BuildContext context, Widget icon) { - return RaisedButton.icon( + return ElevatedButton.icon( onPressed: actualOnPressed, - textColor: textColor, - color: color, - shape: shape, + style: style, icon: icon, label: actualChild, ); @@ -288,15 +238,15 @@ class FancyFab extends _FancyButton { /// /// [child] and [isLoading] must not be null. const FancyFab({ - Key key, - bool isEnabled, - @required VoidCallback onPressed, - @required Widget child, + Key? key, + bool? isEnabled, + required VoidCallback? onPressed, + required Widget child, bool isLoading = false, - Widget loadingLabel, - Widget loadingIndicator, - Color color, - ShapeBorder shape, + Widget? loadingLabel, + Widget? loadingIndicator, + this.backgroundColor, + this.shape, }) : reverseChildren = false, super( key: key, @@ -306,8 +256,6 @@ class FancyFab extends _FancyButton { isLoading: isLoading, loadingIndicator: loadingIndicator, loadingChild: loadingLabel, - color: color, - shape: shape, ); /// Creates an extended [FloatingActionButton]. @@ -316,20 +264,18 @@ class FancyFab extends _FancyButton { /// /// [icon], [child] and [isLoading] must not be null. const FancyFab.extended({ - Key key, - bool isEnabled, - @required VoidCallback onPressed, - @required Widget icon, - @required Widget label, + Key? key, + bool? isEnabled, + required VoidCallback? onPressed, + required Widget icon, + required Widget label, bool isLoading = false, - Widget loadingLabel, - Widget loadingIndicator, - Color backgroundColor, - ShapeBorder shape, + Widget? loadingLabel, + Widget? loadingIndicator, + this.backgroundColor, + this.shape, this.reverseChildren = false, - }) : assert(icon != null), - assert(reverseChildren != null), - super( + }) : super( key: key, isEnabled: isEnabled, onPressed: onPressed, @@ -338,10 +284,11 @@ class FancyFab extends _FancyButton { isLoading: isLoading, loadingIndicator: loadingIndicator, loadingChild: loadingLabel, - color: backgroundColor, - shape: shape, ); + final Color? backgroundColor; + final ShapeBorder? shape; + final bool reverseChildren; @override @@ -381,17 +328,15 @@ class FancyFab extends _FancyButton { ); } - Color _foregroundColor(BuildContext context) { - if (isActuallyEnabled) { - return null; - } - return _backgroundColor(context).disabledOnColor; + Color? _foregroundColor(BuildContext context) { + if (isActuallyEnabled) return null; + + return _backgroundColor(context)?.disabledOnColor; } - Color _backgroundColor(BuildContext context) { - if (isActuallyEnabled) { - return color; - } + Color? _backgroundColor(BuildContext context) { + if (isActuallyEnabled) return backgroundColor; + return Color.alphaBlend( context.theme.disabledColor, context.theme.scaffoldBackgroundColor, @@ -407,57 +352,49 @@ abstract class _FancyButton extends StatelessWidget { /// - `onPressed: null` /// {@endtemplate} const _FancyButton({ - Key key, + Key? key, this.isEnabled, - @required this.onPressed, + required this.onPressed, this.isLoading = false, this.loadingIndicator, this.loadingChild, - this.textColor, - this.color, - this.shape, + this.style, this.icon, - @required this.child, - }) : assert(!(isEnabled == true && onPressed == null), - 'When explicitly setting isEnabled to true, onPressed must not be null'), - assert(isLoading != null), - assert(child != null), + required this.child, + }) : assert( + !(isEnabled == true && onPressed == null), + 'When explicitly setting isEnabled to true, onPressed must not be null', + ), super(key: key); - final bool isEnabled; + final bool? isEnabled; bool get isActuallyEnabled => (isEnabled ?? onPressed != null) && !isLoading; - final VoidCallback onPressed; - VoidCallback get actualOnPressed => isActuallyEnabled ? onPressed : null; + final VoidCallback? onPressed; + VoidCallback? get actualOnPressed => isActuallyEnabled ? onPressed : null; final bool isLoading; - final Widget loadingIndicator; + final Widget? loadingIndicator; Widget get actualLoadingIndicator => loadingIndicator ?? _LoadingIndicator(loadingIndicatorSize); - final Widget loadingChild; + final Widget? loadingChild; Widget get actualLoadingChild => loadingChild ?? child; @visibleForOverriding double get loadingIndicatorSize => 18; - final Color textColor; - final Color color; - final ShapeBorder shape; + final ButtonStyle? style; - final Widget icon; + final Widget? icon; final Widget child; Widget get actualChild => isLoading ? actualLoadingChild : child; @override @nonVirtual Widget build(BuildContext context) { - if (isLoading) { - return _buildIcon(context, actualLoadingIndicator); - } - if (icon != null) { - return _buildIcon(context, icon); - } + if (isLoading) return _buildIcon(context, actualLoadingIndicator); + if (icon != null) return _buildIcon(context, icon!); return _buildDefault(context); } @@ -468,7 +405,7 @@ abstract class _FancyButton extends StatelessWidget { } class _LoadingIndicator extends StatelessWidget { - const _LoadingIndicator(this.size) : assert(size != null); + const _LoadingIndicator(this.size); final double size; diff --git a/lib/src/widgets/chip_group.dart b/lib/src/widgets/chip_group.dart index eeb92df..d16f880 100644 --- a/lib/src/widgets/chip_group.dart +++ b/lib/src/widgets/chip_group.dart @@ -5,15 +5,14 @@ import '../context.dart'; /// Wraps multiple [Chip]s and can optionally show a [title] above these. class ChipGroup extends StatelessWidget { const ChipGroup({ - Key key, + Key? key, this.title, - @required this.children, - }) : assert(children != null), - super(key: key); + required this.children, + }) : super(key: key); /// An optional [Widget] that is displayed above the [children] if there are /// any. - final Widget title; + final Widget? title; final List children; @override @@ -30,8 +29,8 @@ class ChipGroup extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ DefaultTextStyle( - style: context.textTheme.overline, - child: title, + style: context.textTheme.overline!, + child: title!, ), child, ], diff --git a/lib/src/widgets/fill_or_wrap.dart b/lib/src/widgets/fill_or_wrap.dart index 23b0f3f..d0ec6bc 100644 --- a/lib/src/widgets/fill_or_wrap.dart +++ b/lib/src/widgets/fill_or_wrap.dart @@ -1,8 +1,9 @@ import 'dart:math' as math; -import 'package:dartx/dartx.dart'; +import 'package:collection/collection.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; +import 'package:supercharged/supercharged.dart'; import '../render_object.dart'; @@ -18,13 +19,11 @@ import '../render_object.dart'; /// with [MainAxisSize.min]. class FillOrWrap extends MultiChildRenderObjectWidget { FillOrWrap({ - Key key, + Key? key, this.spacing = 0, this.wrappedSpacing = 0, - @required List children, - }) : assert(spacing != null), - assert(wrappedSpacing != null), - super(key: key, children: children); + required List children, + }) : super(key: key, children: children); /// How much space to place between children when not wrapping. final double spacing; @@ -60,15 +59,12 @@ class _FillOrWrapLayout extends RenderBox _FillOrWrapLayout({ double spacing = 0, double wrappedSpacing = 0, - }) : assert(spacing != null), - _spacing = spacing, - assert(wrappedSpacing != null), + }) : _spacing = spacing, _wrappedSpacing = wrappedSpacing; double _spacing; double get spacing => _spacing; set spacing(double value) { - assert(value != null); if (_spacing == value) { return; } @@ -80,7 +76,6 @@ class _FillOrWrapLayout extends RenderBox double _wrappedSpacing; double get wrappedSpacing => _wrappedSpacing; set wrappedSpacing(double value) { - assert(value != null); if (_wrappedSpacing == value) { return; } @@ -89,7 +84,7 @@ class _FillOrWrapLayout extends RenderBox markNeedsLayout(); } - int get _spacingCount => (childCount - 1).coerceAtLeast(0); + int get _spacingCount => math.max(childCount - 1, 0); @override void setupParentData(RenderObject child) { @@ -100,11 +95,11 @@ class _FillOrWrapLayout extends RenderBox @override double computeMinIntrinsicWidth(double height) => - children.map((c) => c.getMinIntrinsicWidth(double.infinity)).max(); + children.map((c) => c.getMinIntrinsicWidth(double.infinity)).max() ?? 0; @override double computeMaxIntrinsicWidth(double height) => - children.sumBy((c) => c.getMaxIntrinsicWidth(double.infinity)); + children.sumByDouble((c) => c.getMaxIntrinsicWidth(double.infinity)); @override double computeMinIntrinsicHeight(double width) => @@ -158,8 +153,8 @@ class _FillOrWrapLayout extends RenderBox } size = Size(constraints.maxWidth, height); - children.forEachIndexed((child, index) { - (child.parentData as _FillOrWrapParentData).offset = Offset( + children.forEachIndexed((index, child) { + (child.parentData! as _FillOrWrapParentData).offset = Offset( index * (childWidth + spacing), (size.height - child.size.height) / 2, ); @@ -178,7 +173,7 @@ class _FillOrWrapLayout extends RenderBox var y = 0.0; for (final child in children) { - (child.parentData as _FillOrWrapParentData).offset = + (child.parentData! as _FillOrWrapParentData).offset = Offset((size.width - child.size.width) / 2, y); y += child.size.height + wrappedSpacing; } @@ -187,9 +182,8 @@ class _FillOrWrapLayout extends RenderBox } @override - bool hitTestChildren(BoxHitTestResult result, {Offset position}) { - return defaultHitTestChildren(result, position: position); - } + bool hitTestChildren(BoxHitTestResult result, {required Offset position}) => + defaultHitTestChildren(result, position: position); @override void paint(PaintingContext context, Offset offset) { @@ -198,11 +192,13 @@ class _FillOrWrapLayout extends RenderBox return; } - if (size.width <= 0) { - return; - } + if (size.width <= 0) return; context.pushClipRect( - needsCompositing, offset, Offset.zero & size, defaultPaint); + needsCompositing, + offset, + Offset.zero & size, + defaultPaint, + ); } } diff --git a/lib/src/widgets/separated_buttons.dart b/lib/src/widgets/separated_buttons.dart index 31c9168..eadb63a 100644 --- a/lib/src/widgets/separated_buttons.dart +++ b/lib/src/widgets/separated_buttons.dart @@ -1,18 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:dartx/dartx.dart'; +import 'package:supercharged/supercharged.dart'; import '../context.dart'; /// A container wrapping multiple buttons with an interpunct (Β·) between each -/// one. It's recommended to use [FlatButton]s as children. +/// one. It's recommended to use [TextButton]s as children. class SeparatedButtons extends StatelessWidget { - const SeparatedButtons({ - Key key, - @required this.children, - }) : assert(children != null), - // Iterable.isEmpty isn't const… - // ignore: prefer_is_empty - assert(children.length > 0), + const SeparatedButtons({Key? key, required this.children}) + : assert(children.length > 0), super(key: key); final List children; @@ -23,7 +18,7 @@ class SeparatedButtons extends StatelessWidget { alignment: WrapAlignment.center, crossAxisAlignment: WrapCrossAlignment.center, children: [ - for (final child in children.dropLast(1)) ...[ + for (final child in children.withoutLast()) ...[ child, Text('β‹…', style: context.theme.textTheme.headline5), ], diff --git a/lib/src/widgets/title_and_subtitle.dart b/lib/src/widgets/title_and_subtitle.dart index 8248417..48649d4 100644 --- a/lib/src/widgets/title_and_subtitle.dart +++ b/lib/src/widgets/title_and_subtitle.dart @@ -1,14 +1,15 @@ import 'package:flutter/material.dart'; -import 'package:black_hole_flutter/black_hole_flutter.dart'; + +import '../context.dart'; /// Shows a title and a subtitle in a [Column]. /// /// It's recommended to use this widget inside an [AppBar]. class TitleAndSubtitle extends StatelessWidget { const TitleAndSubtitle({ - @required this.title, + required this.title, this.subtitle, - }) : assert(title != null); + }); /// See [AppBar.title]. final Widget title; @@ -16,13 +17,11 @@ class TitleAndSubtitle extends StatelessWidget { /// A widget displayed below the title. /// /// Typically a [Text] widget. - final Widget subtitle; + final Widget? subtitle; @override Widget build(BuildContext context) { - if (subtitle == null) { - return title; - } + if (subtitle == null) return title; return Column( mainAxisSize: MainAxisSize.min, @@ -31,7 +30,7 @@ class TitleAndSubtitle extends StatelessWidget { title, DefaultTextStyle.merge( style: context.textTheme.subtitle2, - child: subtitle, + child: subtitle!, ), ], ); diff --git a/pubspec.yaml b/pubspec.yaml index c70cea9..43468eb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,18 +1,19 @@ name: black_hole_flutter -description: "πŸ›  A package absorbing all Flutter utility functions, including extension functions and commonly used widgets" version: 0.2.16 +description: 'πŸ›  A package absorbing all Flutter utility functions, including extension functions and commonly used widgets' homepage: https://github.com/JonasWanke/black_hole_flutter environment: - sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.24.0-7.0.pre" + sdk: '>=2.12.0-0 <3.0.0' + flutter: '>=1.24.0-7.0.pre' dependencies: - dartx: ^0.5.0 + collection: ^1.15.0 flutter: sdk: flutter - meta: ^1.1.8 + meta: ^1.3.0 + supercharged: ^2.0.0-nullsafety.2 dev_dependencies: - extra_pedantic: ^1.2.0 + extra_pedantic: ^1.3.0 test: ^1.6.0